iphlpapi: Remove the no longer needed getNumRoutes and GetNumWithOneHeader functions.
[wine/hacks.git] / dlls / comdlg32 / filedlg.c
bloba2826c8103c81a509d1cdf1eeaaea5d1e2ec82a8
1 /*
2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING,
41 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
42 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
44 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
49 #include "config.h"
50 #include "wine/port.h"
52 #include <ctype.h>
53 #include <stdlib.h>
54 #include <stdarg.h>
55 #include <stdio.h>
56 #include <string.h>
58 #define COBJMACROS
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
62 #include "windef.h"
63 #include "winbase.h"
64 #include "winternl.h"
65 #include "winnls.h"
66 #include "wingdi.h"
67 #include "winreg.h"
68 #include "winuser.h"
69 #include "commdlg.h"
70 #include "dlgs.h"
71 #include "cdlg.h"
72 #include "filedlg31.h"
73 #include "cderr.h"
74 #include "shellapi.h"
75 #include "shlobj.h"
76 #include "filedlgbrowser.h"
77 #include "shlwapi.h"
79 #include "wine/unicode.h"
80 #include "wine/debug.h"
82 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
84 #define UNIMPLEMENTED_FLAGS \
85 (OFN_DONTADDTORECENT |\
86 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
87 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
88 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
90 #define IsHooked(fodInfos) \
91 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
92 /***********************************************************************
93 * Data structure and global variables
95 typedef struct SFolder
97 int m_iImageIndex; /* Index of picture in image list */
98 HIMAGELIST hImgList;
99 int m_iIndent; /* Indentation index */
100 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
102 } SFOLDER,*LPSFOLDER;
104 typedef struct tagLookInInfo
106 int iMaxIndentation;
107 UINT uSelectedItem;
108 } LookInInfos;
110 typedef struct tagFD32_PRIVATE
112 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
113 } FD32_PRIVATE, *PFD32_PRIVATE;
116 /***********************************************************************
117 * Defines and global variables
120 /* Draw item constant */
121 #define ICONWIDTH 18
122 #define XTEXTOFFSET 3
124 /* AddItem flags*/
125 #define LISTEND -1
127 /* SearchItem methods */
128 #define SEARCH_PIDL 1
129 #define SEARCH_EXP 2
130 #define ITEM_NOTFOUND -1
132 /* Undefined windows message sent by CreateViewObject*/
133 #define WM_GETISHELLBROWSER WM_USER+7
135 /* NOTE
136 * Those macros exist in windowsx.h. However, you can't really use them since
137 * they rely on the UNICODE defines and can't be used inside Wine itself.
140 /* Combo box macros */
141 #define CBAddString(hwnd,str) \
142 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
144 #define CBInsertString(hwnd,str,pos) \
145 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
147 #define CBDeleteString(hwnd,pos) \
148 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
150 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
151 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
153 #define CBGetItemDataPtr(hwnd,iItemId) \
154 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
156 #define CBGetLBText(hwnd,iItemId,str) \
157 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
159 #define CBGetCurSel(hwnd) \
160 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
162 #define CBSetCurSel(hwnd,pos) \
163 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
165 #define CBGetCount(hwnd) \
166 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
167 #define CBShowDropDown(hwnd,show) \
168 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
169 #define CBSetItemHeight(hwnd,index,height) \
170 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
172 #define CBSetExtendedUI(hwnd,flag) \
173 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
175 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
176 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
178 /***********************************************************************
179 * Prototypes
182 /* Internal functions used by the dialog */
183 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
184 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
185 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
186 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
187 static BOOL FILEDLG95_OnOpen(HWND hwnd);
188 static LRESULT FILEDLG95_InitControls(HWND hwnd);
189 static void FILEDLG95_Clean(HWND hwnd);
191 /* Functions used by the shell navigation */
192 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
193 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
194 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
195 static void FILEDLG95_SHELL_Clean(HWND hwnd);
196 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
198 /* Functions used by the EDIT box */
199 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
201 /* Functions used by the filetype combo box */
202 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
203 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
204 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
205 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
207 /* Functions used by the Look In combo box */
208 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
209 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
210 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
211 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
212 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
213 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
214 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
215 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
216 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
218 /* Miscellaneous tool functions */
219 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
220 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
221 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
222 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
223 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
224 static UINT GetNumSelected( IDataObject *doSelected );
226 /* Shell memory allocation */
227 static void *MemAlloc(UINT size);
228 static void MemFree(void *mem);
230 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
231 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
232 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
233 static BOOL BrowseSelectedFolder(HWND hwnd);
235 /***********************************************************************
236 * GetFileName95
238 * Creates an Open common dialog box that lets the user select
239 * the drive, directory, and the name of a file or set of files to open.
241 * IN : The FileOpenDlgInfos structure associated with the dialog
242 * OUT : TRUE on success
243 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
245 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
248 LRESULT lRes;
249 LPCVOID template;
250 HRSRC hRes;
251 HANDLE hDlgTmpl = 0;
252 HRESULT hr;
254 /* test for missing functionality */
255 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
257 FIXME("Flags 0x%08x not yet implemented\n",
258 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
261 /* Create the dialog from a template */
263 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
265 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
266 return FALSE;
268 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
269 !(template = LockResource( hDlgTmpl )))
271 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
272 return FALSE;
275 /* old style hook messages */
276 if (IsHooked(fodInfos))
278 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
279 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
280 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
281 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
284 /* Some shell namespace extensions depend on COM being initialized. */
285 hr = OleInitialize(NULL);
287 if (fodInfos->unicode)
288 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
289 template,
290 fodInfos->ofnInfos->hwndOwner,
291 FileOpenDlgProc95,
292 (LPARAM) fodInfos);
293 else
294 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
295 template,
296 fodInfos->ofnInfos->hwndOwner,
297 FileOpenDlgProc95,
298 (LPARAM) fodInfos);
299 if (SUCCEEDED(hr))
300 OleUninitialize();
302 /* Unable to create the dialog */
303 if( lRes == -1)
304 return FALSE;
306 return lRes;
309 /***********************************************************************
310 * GetFileDialog95A
312 * Call GetFileName95 with this structure and clean the memory.
314 * IN : The OPENFILENAMEA initialisation structure passed to
315 * GetOpenFileNameA win api function (see filedlg.c)
317 static BOOL GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
319 BOOL ret;
320 FileOpenDlgInfos fodInfos;
321 LPSTR lpstrSavDir = NULL;
322 LPWSTR title = NULL;
323 LPWSTR defext = NULL;
324 LPWSTR filter = NULL;
325 LPWSTR customfilter = NULL;
327 /* Initialize CommDlgExtendedError() */
328 COMDLG32_SetCommDlgExtendedError(0);
330 /* Initialize FileOpenDlgInfos structure */
331 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
333 /* Pass in the original ofn */
334 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
336 /* save current directory */
337 if (ofn->Flags & OFN_NOCHANGEDIR)
339 lpstrSavDir = MemAlloc(MAX_PATH);
340 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
343 fodInfos.unicode = FALSE;
345 /* convert all the input strings to unicode */
346 if(ofn->lpstrInitialDir)
348 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
349 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
350 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
352 else
353 fodInfos.initdir = NULL;
355 if(ofn->lpstrFile)
357 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
358 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
360 else
361 fodInfos.filename = NULL;
363 if(ofn->lpstrDefExt)
365 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
366 defext = MemAlloc((len+1)*sizeof(WCHAR));
367 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
369 fodInfos.defext = defext;
371 if(ofn->lpstrTitle)
373 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
374 title = MemAlloc((len+1)*sizeof(WCHAR));
375 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
377 fodInfos.title = title;
379 if (ofn->lpstrFilter)
381 LPCSTR s;
382 int n, len;
384 /* filter is a list... title\0ext\0......\0\0 */
385 s = ofn->lpstrFilter;
386 while (*s) s = s+strlen(s)+1;
387 s++;
388 n = s - ofn->lpstrFilter;
389 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
390 filter = MemAlloc(len*sizeof(WCHAR));
391 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
393 fodInfos.filter = filter;
395 /* convert lpstrCustomFilter */
396 if (ofn->lpstrCustomFilter)
398 LPCSTR s;
399 int n, len;
401 /* customfilter contains a pair of strings... title\0ext\0 */
402 s = ofn->lpstrCustomFilter;
403 if (*s) s = s+strlen(s)+1;
404 if (*s) s = s+strlen(s)+1;
405 n = s - ofn->lpstrCustomFilter;
406 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
407 customfilter = MemAlloc(len*sizeof(WCHAR));
408 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
410 fodInfos.customfilter = customfilter;
412 /* Initialize the dialog property */
413 fodInfos.DlgInfos.dwDlgProp = 0;
414 fodInfos.DlgInfos.hwndCustomDlg = NULL;
416 switch(iDlgType)
418 case OPEN_DIALOG :
419 ret = GetFileName95(&fodInfos);
420 break;
421 case SAVE_DIALOG :
422 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
423 ret = GetFileName95(&fodInfos);
424 break;
425 default :
426 ret = 0;
429 if (lpstrSavDir)
431 SetCurrentDirectoryA(lpstrSavDir);
432 MemFree(lpstrSavDir);
435 MemFree(title);
436 MemFree(defext);
437 MemFree(filter);
438 MemFree(customfilter);
439 MemFree(fodInfos.initdir);
440 MemFree(fodInfos.filename);
442 TRACE("selected file: %s\n",ofn->lpstrFile);
444 return ret;
447 /***********************************************************************
448 * GetFileDialog95W
450 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
451 * Call GetFileName95 with this structure and clean the memory.
454 static BOOL GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
456 BOOL ret;
457 FileOpenDlgInfos fodInfos;
458 LPWSTR lpstrSavDir = NULL;
460 /* Initialize CommDlgExtendedError() */
461 COMDLG32_SetCommDlgExtendedError(0);
463 /* Initialize FileOpenDlgInfos structure */
464 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
466 /* Pass in the original ofn */
467 fodInfos.ofnInfos = ofn;
469 fodInfos.title = ofn->lpstrTitle;
470 fodInfos.defext = ofn->lpstrDefExt;
471 fodInfos.filter = ofn->lpstrFilter;
472 fodInfos.customfilter = ofn->lpstrCustomFilter;
474 /* convert string arguments, save others */
475 if(ofn->lpstrFile)
477 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
478 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
480 else
481 fodInfos.filename = NULL;
483 if(ofn->lpstrInitialDir)
485 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
486 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
487 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
488 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
490 else
491 fodInfos.initdir = NULL;
493 /* save current directory */
494 if (ofn->Flags & OFN_NOCHANGEDIR)
496 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
497 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
500 fodInfos.unicode = TRUE;
502 switch(iDlgType)
504 case OPEN_DIALOG :
505 ret = GetFileName95(&fodInfos);
506 break;
507 case SAVE_DIALOG :
508 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
509 ret = GetFileName95(&fodInfos);
510 break;
511 default :
512 ret = 0;
515 if (lpstrSavDir)
517 SetCurrentDirectoryW(lpstrSavDir);
518 MemFree(lpstrSavDir);
521 /* restore saved IN arguments and convert OUT arguments back */
522 MemFree(fodInfos.filename);
523 MemFree(fodInfos.initdir);
524 return ret;
527 /******************************************************************************
528 * COMDLG32_GetDisplayNameOf [internal]
530 * Helper function to get the display name for a pidl.
532 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
533 LPSHELLFOLDER psfDesktop;
534 STRRET strret;
536 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
537 return FALSE;
539 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
540 IShellFolder_Release(psfDesktop);
541 return FALSE;
544 IShellFolder_Release(psfDesktop);
545 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
548 /***********************************************************************
549 * ArrangeCtrlPositions [internal]
551 * NOTE: Do not change anything here without a lot of testing.
553 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
555 HWND hwndChild, hwndStc32;
556 RECT rectParent, rectChild, rectStc32;
557 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
559 /* Take into account if open as read only checkbox and help button
560 * are hidden
562 if (hide_help)
564 RECT rectHelp, rectCancel;
565 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
566 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
567 /* subtract the height of the help button plus the space between
568 * the help button and the cancel button to the height of the dialog
570 help_fixup = rectHelp.bottom - rectCancel.bottom;
574 There are two possibilities to add components to the default file dialog box.
576 By default, all the new components are added below the standard dialog box (the else case).
578 However, if there is a static text component with the stc32 id, a special case happens.
579 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
580 in the window and the cx and cy indicate how to size the window.
581 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
582 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
586 GetClientRect(hwndParentDlg, &rectParent);
588 /* when arranging controls we have to use fixed parent size */
589 rectParent.bottom -= help_fixup;
591 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
592 if (hwndStc32)
594 GetWindowRect(hwndStc32, &rectStc32);
595 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
597 /* set the size of the stc32 control according to the size of
598 * client area of the parent dialog
600 SetWindowPos(hwndStc32, 0,
601 0, 0,
602 rectParent.right, rectParent.bottom,
603 SWP_NOMOVE | SWP_NOZORDER);
605 else
606 SetRectEmpty(&rectStc32);
608 /* this part moves controls of the child dialog */
609 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
610 while (hwndChild)
612 if (hwndChild != hwndStc32)
614 GetWindowRect(hwndChild, &rectChild);
615 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
617 /* move only if stc32 exist */
618 if (hwndStc32 && rectChild.left > rectStc32.right)
620 LONG old_left = rectChild.left;
622 /* move to the right of visible controls of the parent dialog */
623 rectChild.left += rectParent.right;
624 rectChild.left -= rectStc32.right;
626 child_width_fixup = rectChild.left - old_left;
628 /* move even if stc32 doesn't exist */
629 if (rectChild.top >= rectStc32.bottom)
631 LONG old_top = rectChild.top;
633 /* move below visible controls of the parent dialog */
634 rectChild.top += rectParent.bottom;
635 rectChild.top -= rectStc32.bottom - rectStc32.top;
637 child_height_fixup = rectChild.top - old_top;
640 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
641 0, 0, SWP_NOSIZE | SWP_NOZORDER);
643 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
646 /* this part moves controls of the parent dialog */
647 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
648 while (hwndChild)
650 if (hwndChild != hwndChildDlg)
652 GetWindowRect(hwndChild, &rectChild);
653 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
655 /* left,top of stc32 marks the position of controls
656 * from the parent dialog
658 rectChild.left += rectStc32.left;
659 rectChild.top += rectStc32.top;
661 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
662 0, 0, SWP_NOSIZE | SWP_NOZORDER);
664 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
667 /* calculate the size of the resulting dialog */
669 /* here we have to use original parent size */
670 GetClientRect(hwndParentDlg, &rectParent);
671 GetClientRect(hwndChildDlg, &rectChild);
673 if (hwndStc32)
675 rectChild.right += child_width_fixup;
676 rectChild.bottom += child_height_fixup;
678 if (rectParent.right > rectChild.right)
680 rectParent.right += rectChild.right;
681 rectParent.right -= rectStc32.right - rectStc32.left;
683 else
685 rectParent.right = rectChild.right;
688 if (rectParent.bottom > rectChild.bottom)
690 rectParent.bottom += rectChild.bottom;
691 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
693 else
695 /* child dialog is higher, unconditionally set new dialog
696 * height to its size (help_fixup will be subtracted below)
698 rectParent.bottom = rectChild.bottom + help_fixup;
701 else
703 rectParent.bottom += rectChild.bottom;
706 /* finally use fixed parent size */
707 rectParent.bottom -= help_fixup;
709 /* set the size of the parent dialog */
710 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
711 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
712 SetWindowPos(hwndParentDlg, 0,
713 0, 0,
714 rectParent.right - rectParent.left,
715 rectParent.bottom - rectParent.top,
716 SWP_NOMOVE | SWP_NOZORDER);
719 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
721 switch(uMsg) {
722 case WM_INITDIALOG:
723 return TRUE;
725 return FALSE;
728 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
730 LPCVOID template;
731 HRSRC hRes;
732 HANDLE hDlgTmpl = 0;
733 HWND hChildDlg = 0;
735 TRACE("\n");
738 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
739 * structure's hInstance parameter is not a HINSTANCE, but
740 * instead a pointer to a template resource to use.
742 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
744 HINSTANCE hinst;
745 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
747 hinst = COMDLG32_hInstance;
748 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
750 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
751 return NULL;
754 else
756 hinst = fodInfos->ofnInfos->hInstance;
757 if(fodInfos->unicode)
759 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
760 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
762 else
764 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
765 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
767 if (!hRes)
769 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
770 return NULL;
772 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
773 !(template = LockResource( hDlgTmpl )))
775 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
776 return NULL;
779 if (fodInfos->unicode)
780 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
781 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
782 (LPARAM)fodInfos->ofnInfos);
783 else
784 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
785 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
786 (LPARAM)fodInfos->ofnInfos);
787 if(hChildDlg)
789 ShowWindow(hChildDlg,SW_SHOW);
790 return hChildDlg;
793 else if( IsHooked(fodInfos))
795 RECT rectHwnd;
796 struct {
797 DLGTEMPLATE tmplate;
798 WORD menu,class,title;
799 } temp;
800 GetClientRect(hwnd,&rectHwnd);
801 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
802 temp.tmplate.dwExtendedStyle = 0;
803 temp.tmplate.cdit = 0;
804 temp.tmplate.x = 0;
805 temp.tmplate.y = 0;
806 temp.tmplate.cx = 0;
807 temp.tmplate.cy = 0;
808 temp.menu = temp.class = temp.title = 0;
810 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
811 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
813 return hChildDlg;
815 return NULL;
818 /***********************************************************************
819 * SendCustomDlgNotificationMessage
821 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
824 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
826 LRESULT hook_result = 0;
827 FileOpenDlgInfos *fodInfos = 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 result)
864 UINT len, total;
865 WCHAR *p, *buffer;
866 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
868 TRACE("CDM_GETFILEPATH:\n");
870 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
871 return -1;
873 /* get path and filenames */
874 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
875 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
876 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
877 if (len)
879 p = buffer + strlenW(buffer);
880 *p++ = '\\';
881 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
883 if (fodInfos->unicode)
885 total = strlenW( buffer) + 1;
886 if (result) lstrcpynW( result, buffer, size );
887 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
889 else
891 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
892 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
893 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
895 HeapFree( GetProcessHeap(), 0, buffer );
896 return total;
899 /***********************************************************************
900 * FILEDLG95_HandleCustomDialogMessages
902 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
904 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
906 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
907 WCHAR lpstrPath[MAX_PATH];
908 INT_PTR retval;
910 if(!fodInfos) return FALSE;
912 switch(uMsg)
914 case CDM_GETFILEPATH:
915 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
916 break;
918 case CDM_GETFOLDERPATH:
919 TRACE("CDM_GETFOLDERPATH:\n");
920 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
921 if (lParam)
923 if (fodInfos->unicode)
924 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
925 else
926 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
927 (LPSTR)lParam, (int)wParam, NULL, NULL);
929 retval = lstrlenW(lpstrPath);
930 break;
932 case CDM_GETFOLDERIDLIST:
933 retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
934 if (retval <= wParam)
935 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
936 break;
938 case CDM_GETSPEC:
939 TRACE("CDM_GETSPEC:\n");
940 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
941 if (lParam)
943 if (fodInfos->unicode)
944 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
945 else
946 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
948 break;
950 case CDM_SETCONTROLTEXT:
951 TRACE("CDM_SETCONTROLTEXT:\n");
952 if ( lParam )
954 if( fodInfos->unicode )
955 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
956 else
957 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
959 retval = TRUE;
960 break;
962 case CDM_HIDECONTROL:
963 /* MSDN states that it should fail for not OFN_EXPLORER case */
964 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
966 HWND control = GetDlgItem( hwnd, wParam );
967 if (control) ShowWindow( control, SW_HIDE );
968 retval = TRUE;
970 else retval = FALSE;
971 break;
973 default:
974 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
975 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
976 return FALSE;
978 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
979 return TRUE;
982 /***********************************************************************
983 * FileOpenDlgProc95
985 * File open dialog procedure
987 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
989 #if 0
990 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
991 #endif
993 switch(uMsg)
995 case WM_INITDIALOG:
997 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
999 /* Adds the FileOpenDlgInfos in the property list of the dialog
1000 so it will be easily accessible through a GetPropA(...) */
1001 SetPropA(hwnd, FileOpenDlgInfosStr, fodInfos);
1003 FILEDLG95_InitControls(hwnd);
1005 fodInfos->DlgInfos.hwndCustomDlg =
1006 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1008 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1009 FILEDLG95_FillControls(hwnd, wParam, lParam);
1011 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1012 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1013 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1014 return 0;
1016 case WM_COMMAND:
1017 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1018 case WM_DRAWITEM:
1020 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1022 case IDC_LOOKIN:
1023 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1024 return TRUE;
1027 return FALSE;
1029 case WM_GETISHELLBROWSER:
1030 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1032 case WM_DESTROY:
1033 RemovePropA(hwnd, FileOpenDlgInfosStr);
1034 return FALSE;
1036 case WM_NOTIFY:
1038 LPNMHDR lpnmh = (LPNMHDR)lParam;
1039 UINT stringId = -1;
1041 /* set up the button tooltips strings */
1042 if(TTN_GETDISPINFOA == lpnmh->code )
1044 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1045 switch(lpnmh->idFrom )
1047 /* Up folder button */
1048 case FCIDM_TB_UPFOLDER:
1049 stringId = IDS_UPFOLDER;
1050 break;
1051 /* New folder button */
1052 case FCIDM_TB_NEWFOLDER:
1053 stringId = IDS_NEWFOLDER;
1054 break;
1055 /* List option button */
1056 case FCIDM_TB_SMALLICON:
1057 stringId = IDS_LISTVIEW;
1058 break;
1059 /* Details option button */
1060 case FCIDM_TB_REPORTVIEW:
1061 stringId = IDS_REPORTVIEW;
1062 break;
1063 /* Desktop button */
1064 case FCIDM_TB_DESKTOP:
1065 stringId = IDS_TODESKTOP;
1066 break;
1067 default:
1068 stringId = 0;
1070 lpdi->hinst = COMDLG32_hInstance;
1071 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1073 return FALSE;
1075 default :
1076 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1077 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1078 return FALSE;
1082 /***********************************************************************
1083 * FILEDLG95_InitControls
1085 * WM_INITDIALOG message handler (before hook notification)
1087 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1089 int win2000plus = 0;
1090 int win98plus = 0;
1091 int handledPath = FALSE;
1092 OSVERSIONINFOW osVi;
1093 static const WCHAR szwSlash[] = { '\\', 0 };
1094 static const WCHAR szwStar[] = { '*',0 };
1096 static const TBBUTTON tbb[] =
1098 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1099 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1100 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1101 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1102 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1103 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1104 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1105 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1106 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1108 TBADDBITMAP tba[2];
1109 RECT rectTB;
1110 RECT rectlook;
1111 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1113 tba[0].hInst = HINST_COMMCTRL;
1114 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1115 tba[1].hInst = COMDLG32_hInstance;
1116 tba[1].nID = 800;
1118 TRACE("%p\n", fodInfos);
1120 /* Get windows version emulating */
1121 osVi.dwOSVersionInfoSize = sizeof(osVi);
1122 GetVersionExW(&osVi);
1123 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1124 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1125 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1126 win2000plus = (osVi.dwMajorVersion > 4);
1127 if (win2000plus) win98plus = TRUE;
1129 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1131 /* Get the hwnd of the controls */
1132 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1133 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1134 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1136 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1137 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1139 /* construct the toolbar */
1140 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1141 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1143 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1144 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1145 rectTB.left = rectlook.right;
1146 rectTB.top = rectlook.top-1;
1148 if (fodInfos->unicode)
1149 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1150 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1151 rectTB.left, rectTB.top,
1152 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1153 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1154 else
1155 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1156 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1157 rectTB.left, rectTB.top,
1158 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1159 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1161 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1163 /* FIXME: use TB_LOADIMAGES when implemented */
1164 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1165 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba[0]);
1166 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 1, (LPARAM) &tba[1]);
1168 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1169 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1171 /* Set the window text with the text specified in the OPENFILENAME structure */
1172 if(fodInfos->title)
1174 SetWindowTextW(hwnd,fodInfos->title);
1176 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1178 WCHAR buf[16];
1179 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1180 SetWindowTextW(hwnd, buf);
1183 /* Initialise the file name edit control */
1184 handledPath = FALSE;
1185 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1187 if(fodInfos->filename)
1189 /* 1. If win2000 or higher and filename contains a path, use it
1190 in preference over the lpstrInitialDir */
1191 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1192 WCHAR tmpBuf[MAX_PATH];
1193 WCHAR *nameBit;
1194 DWORD result;
1196 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1197 if (result) {
1199 /* nameBit is always shorter than the original filename */
1200 lstrcpyW(fodInfos->filename,nameBit);
1202 *nameBit = 0x00;
1203 if (fodInfos->initdir == NULL)
1204 MemFree(fodInfos->initdir);
1205 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1206 lstrcpyW(fodInfos->initdir, tmpBuf);
1207 handledPath = TRUE;
1208 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1209 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1211 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1213 } else {
1214 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1218 /* 2. (All platforms) If initdir is not null, then use it */
1219 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1220 (*fodInfos->initdir!=0x00))
1222 /* Work out the proper path as supplied one might be relative */
1223 /* (Here because supplying '.' as dir browses to My Computer) */
1224 if (handledPath==FALSE) {
1225 WCHAR tmpBuf[MAX_PATH];
1226 WCHAR tmpBuf2[MAX_PATH];
1227 WCHAR *nameBit;
1228 DWORD result;
1230 lstrcpyW(tmpBuf, fodInfos->initdir);
1231 if( PathFileExistsW(tmpBuf) ) {
1232 /* initdir does not have to be a directory. If a file is
1233 * specified, the dir part is taken */
1234 if( PathIsDirectoryW(tmpBuf)) {
1235 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1236 lstrcatW(tmpBuf, szwSlash);
1238 lstrcatW(tmpBuf, szwStar);
1240 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1241 if (result) {
1242 *nameBit = 0x00;
1243 MemFree(fodInfos->initdir);
1244 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1245 lstrcpyW(fodInfos->initdir, tmpBuf2);
1246 handledPath = TRUE;
1247 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1250 else if (fodInfos->initdir)
1252 MemFree(fodInfos->initdir);
1253 fodInfos->initdir = NULL;
1254 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1259 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1260 (*fodInfos->initdir==0x00)))
1262 /* 3. All except w2k+: if filename contains a path use it */
1263 if (!win2000plus && fodInfos->filename &&
1264 *fodInfos->filename &&
1265 strpbrkW(fodInfos->filename, szwSlash)) {
1266 WCHAR tmpBuf[MAX_PATH];
1267 WCHAR *nameBit;
1268 DWORD result;
1270 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1271 tmpBuf, &nameBit);
1272 if (result) {
1273 int len;
1275 /* nameBit is always shorter than the original filename */
1276 lstrcpyW(fodInfos->filename, nameBit);
1277 *nameBit = 0x00;
1279 len = lstrlenW(tmpBuf);
1280 MemFree(fodInfos->initdir);
1281 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1282 lstrcpyW(fodInfos->initdir, tmpBuf);
1284 handledPath = TRUE;
1285 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1286 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1288 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1291 /* 4. win98+ and win2000+ if any files of specified filter types in
1292 current directory, use it */
1293 if ( win98plus && handledPath == FALSE &&
1294 fodInfos->filter && *fodInfos->filter) {
1296 BOOL searchMore = TRUE;
1297 LPCWSTR lpstrPos = fodInfos->filter;
1298 WIN32_FIND_DATAW FindFileData;
1299 HANDLE hFind;
1301 while (searchMore)
1303 /* filter is a list... title\0ext\0......\0\0 */
1305 /* Skip the title */
1306 if(! *lpstrPos) break; /* end */
1307 lpstrPos += lstrlenW(lpstrPos) + 1;
1309 /* See if any files exist in the current dir with this extension */
1310 if(! *lpstrPos) break; /* end */
1312 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1314 if (hFind == INVALID_HANDLE_VALUE) {
1315 /* None found - continue search */
1316 lpstrPos += lstrlenW(lpstrPos) + 1;
1318 } else {
1319 searchMore = FALSE;
1321 MemFree(fodInfos->initdir);
1322 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1323 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1325 handledPath = TRUE;
1326 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1327 debugstr_w(lpstrPos));
1328 break;
1333 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1335 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1336 if (handledPath == FALSE && (win2000plus || win98plus)) {
1337 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1339 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1341 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1343 /* last fallback */
1344 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1345 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1346 } else {
1347 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1349 } else {
1350 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1352 handledPath = TRUE;
1353 } else if (handledPath==FALSE) {
1354 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1355 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1356 handledPath = TRUE;
1357 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1360 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1361 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1363 /* Must the open as read only check box be checked ?*/
1364 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1366 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1369 /* Must the open as read only check box be hidden? */
1370 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1372 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1373 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1376 /* Must the help button be hidden? */
1377 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1379 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1380 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1383 /* change Open to Save */
1384 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1386 WCHAR buf[16];
1387 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1388 SetDlgItemTextW(hwnd, IDOK, buf);
1389 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1390 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1393 /* Initialize the filter combo box */
1394 FILEDLG95_FILETYPE_Init(hwnd);
1396 return 0;
1399 /***********************************************************************
1400 * FILEDLG95_ResizeControls
1402 * WM_INITDIALOG message handler (after hook notification)
1404 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1406 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1408 if (fodInfos->DlgInfos.hwndCustomDlg)
1410 RECT rc;
1411 UINT flags = SWP_NOACTIVATE;
1413 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1414 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1416 /* resize the custom dialog to the parent size */
1417 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1418 GetClientRect(hwnd, &rc);
1419 else
1421 /* our own fake template is zero sized and doesn't have children, so
1422 * there is no need to resize it. Picasa depends on it.
1424 flags |= SWP_NOSIZE;
1425 SetRectEmpty(&rc);
1427 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1428 0, 0, rc.right, rc.bottom, flags);
1430 else
1432 /* Resize the height, if open as read only checkbox ad help button are
1433 * hidden and we are not using a custom template nor a customDialog
1435 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1436 (!(fodInfos->ofnInfos->Flags &
1437 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1439 RECT rectDlg, rectHelp, rectCancel;
1440 GetWindowRect(hwnd, &rectDlg);
1441 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1442 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1443 /* subtract the height of the help button plus the space between the help
1444 * button and the cancel button to the height of the dialog
1446 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1447 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1448 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1451 return TRUE;
1454 /***********************************************************************
1455 * FILEDLG95_FillControls
1457 * WM_INITDIALOG message handler (after hook notification)
1459 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1461 LPITEMIDLIST pidlItemId = NULL;
1463 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1465 TRACE("dir=%s file=%s\n",
1466 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1468 /* Get the initial directory pidl */
1470 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1472 WCHAR path[MAX_PATH];
1474 GetCurrentDirectoryW(MAX_PATH,path);
1475 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1478 /* Initialise shell objects */
1479 FILEDLG95_SHELL_Init(hwnd);
1481 /* Initialize the Look In combo box */
1482 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1484 /* Browse to the initial directory */
1485 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1487 /* Free pidlItem memory */
1488 COMDLG32_SHFree(pidlItemId);
1490 return TRUE;
1492 /***********************************************************************
1493 * FILEDLG95_Clean
1495 * Regroups all the cleaning functions of the filedlg
1497 void FILEDLG95_Clean(HWND hwnd)
1499 FILEDLG95_FILETYPE_Clean(hwnd);
1500 FILEDLG95_LOOKIN_Clean(hwnd);
1501 FILEDLG95_SHELL_Clean(hwnd);
1503 /***********************************************************************
1504 * FILEDLG95_OnWMCommand
1506 * WM_COMMAND message handler
1508 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1510 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1511 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1512 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1514 switch(wID)
1516 /* OK button */
1517 case IDOK:
1518 FILEDLG95_OnOpen(hwnd);
1519 break;
1520 /* Cancel button */
1521 case IDCANCEL:
1522 FILEDLG95_Clean(hwnd);
1523 EndDialog(hwnd, FALSE);
1524 break;
1525 /* Filetype combo box */
1526 case IDC_FILETYPE:
1527 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1528 break;
1529 /* LookIn combo box */
1530 case IDC_LOOKIN:
1531 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1532 break;
1534 /* --- toolbar --- */
1535 /* Up folder button */
1536 case FCIDM_TB_UPFOLDER:
1537 FILEDLG95_SHELL_UpFolder(hwnd);
1538 break;
1539 /* New folder button */
1540 case FCIDM_TB_NEWFOLDER:
1541 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1542 break;
1543 /* List option button */
1544 case FCIDM_TB_SMALLICON:
1545 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1546 break;
1547 /* Details option button */
1548 case FCIDM_TB_REPORTVIEW:
1549 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1550 break;
1551 /* Details option button */
1552 case FCIDM_TB_DESKTOP:
1553 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1554 break;
1556 case IDC_FILENAME:
1557 break;
1560 /* Do not use the listview selection anymore */
1561 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1562 return 0;
1565 /***********************************************************************
1566 * FILEDLG95_OnWMGetIShellBrowser
1568 * WM_GETISHELLBROWSER message handler
1570 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1572 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1574 TRACE("\n");
1576 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1578 return TRUE;
1582 /***********************************************************************
1583 * FILEDLG95_SendFileOK
1585 * Sends the CDN_FILEOK notification if required
1587 * RETURNS
1588 * TRUE if the dialog should close
1589 * FALSE if the dialog should not be closed
1591 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1593 /* ask the hook if we can close */
1594 if(IsHooked(fodInfos))
1596 LRESULT retval;
1598 TRACE("---\n");
1599 /* First send CDN_FILEOK as MSDN doc says */
1600 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1601 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1603 TRACE("canceled\n");
1604 return (retval == 0);
1607 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1608 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1609 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1610 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1612 TRACE("canceled\n");
1613 return (retval == 0);
1616 return TRUE;
1619 /***********************************************************************
1620 * FILEDLG95_OnOpenMultipleFiles
1622 * Handles the opening of multiple files.
1624 * FIXME
1625 * check destination buffer size
1627 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1629 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1630 UINT nCount, nSizePath;
1631 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1633 TRACE("\n");
1635 if(fodInfos->unicode)
1637 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1638 ofn->lpstrFile[0] = '\0';
1640 else
1642 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1643 ofn->lpstrFile[0] = '\0';
1646 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1648 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1649 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1650 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1652 LPWSTR lpstrTemp = lpstrFileList;
1654 for ( nCount = 0; nCount < nFileCount; nCount++ )
1656 LPITEMIDLIST pidl;
1658 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1659 if (!pidl)
1661 WCHAR lpstrNotFound[100];
1662 WCHAR lpstrMsg[100];
1663 WCHAR tmp[400];
1664 static const WCHAR nl[] = {'\n',0};
1666 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1667 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1669 lstrcpyW(tmp, lpstrTemp);
1670 lstrcatW(tmp, nl);
1671 lstrcatW(tmp, lpstrNotFound);
1672 lstrcatW(tmp, nl);
1673 lstrcatW(tmp, lpstrMsg);
1675 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1676 return FALSE;
1679 /* move to the next file in the list of files */
1680 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1681 COMDLG32_SHFree(pidl);
1685 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1686 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1688 /* For "oldstyle" dialog the components have to
1689 be separated by blanks (not '\0'!) and short
1690 filenames have to be used! */
1691 FIXME("Components have to be separated by blanks\n");
1693 if(fodInfos->unicode)
1695 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1696 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1697 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1699 else
1701 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1703 if (ofn->lpstrFile != NULL)
1705 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1706 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1707 if (ofn->nMaxFile > nSizePath)
1709 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1710 ofn->lpstrFile + nSizePath,
1711 ofn->nMaxFile - nSizePath, NULL, NULL);
1716 fodInfos->ofnInfos->nFileOffset = nSizePath;
1717 fodInfos->ofnInfos->nFileExtension = 0;
1719 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1720 return FALSE;
1722 /* clean and exit */
1723 FILEDLG95_Clean(hwnd);
1724 return EndDialog(hwnd,TRUE);
1727 /***********************************************************************
1728 * FILEDLG95_OnOpen
1730 * Ok button WM_COMMAND message handler
1732 * If the function succeeds, the return value is nonzero.
1734 #define ONOPEN_BROWSE 1
1735 #define ONOPEN_OPEN 2
1736 #define ONOPEN_SEARCH 3
1737 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1739 WCHAR strMsgTitle[MAX_PATH];
1740 WCHAR strMsgText [MAX_PATH];
1741 if (idCaption)
1742 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1743 else
1744 strMsgTitle[0] = '\0';
1745 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1746 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1749 BOOL FILEDLG95_OnOpen(HWND hwnd)
1751 LPWSTR lpstrFileList;
1752 UINT nFileCount = 0;
1753 UINT sizeUsed = 0;
1754 BOOL ret = TRUE;
1755 WCHAR lpstrPathAndFile[MAX_PATH];
1756 WCHAR lpstrTemp[MAX_PATH];
1757 LPSHELLFOLDER lpsf = NULL;
1758 int nOpenAction;
1759 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1761 TRACE("hwnd=%p\n", hwnd);
1763 /* get the files from the edit control */
1764 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1766 /* try if the user selected a folder in the shellview */
1767 if(nFileCount == 0)
1769 BrowseSelectedFolder(hwnd);
1770 return FALSE;
1773 if(nFileCount > 1)
1775 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1776 goto ret;
1779 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1782 Step 1: Build a complete path name from the current folder and
1783 the filename or path in the edit box.
1784 Special cases:
1785 - the path in the edit box is a root path
1786 (with or without drive letter)
1787 - the edit box contains ".." (or a path with ".." in it)
1790 /* Get the current directory name */
1791 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1793 /* last fallback */
1794 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1796 PathAddBackslashW(lpstrPathAndFile);
1798 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1800 /* if the user specified a fully qualified path use it */
1801 if(PathIsRelativeW(lpstrFileList))
1803 lstrcatW(lpstrPathAndFile, lpstrFileList);
1805 else
1807 /* does the path have a drive letter? */
1808 if (PathGetDriveNumberW(lpstrFileList) == -1)
1809 lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
1810 else
1811 lstrcpyW(lpstrPathAndFile, lpstrFileList);
1814 /* resolve "." and ".." */
1815 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1816 lstrcpyW(lpstrPathAndFile, lpstrTemp);
1817 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1819 MemFree(lpstrFileList);
1822 Step 2: here we have a cleaned up path
1824 We have to parse the path step by step to see if we have to browse
1825 to a folder if the path points to a directory or the last
1826 valid element is a directory.
1828 valid variables:
1829 lpstrPathAndFile: cleaned up path
1832 if (nFileCount &&
1833 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1834 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1835 nOpenAction = ONOPEN_OPEN;
1836 else
1837 nOpenAction = ONOPEN_BROWSE;
1839 /* don't apply any checks with OFN_NOVALIDATE */
1841 LPWSTR lpszTemp, lpszTemp1;
1842 LPITEMIDLIST pidl = NULL;
1843 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1845 /* check for invalid chars */
1846 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1848 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1849 ret = FALSE;
1850 goto ret;
1853 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1855 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1856 while (lpszTemp1)
1858 LPSHELLFOLDER lpsfChild;
1859 WCHAR lpwstrTemp[MAX_PATH];
1860 DWORD dwEaten, dwAttributes;
1861 LPWSTR p;
1863 lstrcpyW(lpwstrTemp, lpszTemp);
1864 p = PathFindNextComponentW(lpwstrTemp);
1866 if (!p) break; /* end of path */
1868 *p = 0;
1869 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
1871 /* There are no wildcards when OFN_NOVALIDATE is set */
1872 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1874 static const WCHAR wszWild[] = { '*', '?', 0 };
1875 /* if the last element is a wildcard do a search */
1876 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1878 nOpenAction = ONOPEN_SEARCH;
1879 break;
1882 lpszTemp1 = lpszTemp;
1884 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1886 /* append a backslash to drive letters */
1887 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1888 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1889 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1891 PathAddBackslashW(lpwstrTemp);
1894 dwAttributes = SFGAO_FOLDER;
1895 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1897 /* the path component is valid, we have a pidl of the next path component */
1898 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
1899 if(dwAttributes & SFGAO_FOLDER)
1901 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1903 ERR("bind to failed\n"); /* should not fail */
1904 break;
1906 IShellFolder_Release(lpsf);
1907 lpsf = lpsfChild;
1908 lpsfChild = NULL;
1910 else
1912 TRACE("value\n");
1914 /* end dialog, return value */
1915 nOpenAction = ONOPEN_OPEN;
1916 break;
1918 COMDLG32_SHFree(pidl);
1919 pidl = NULL;
1921 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1923 if(*lpszTemp || /* points to trailing null for last path element */
1924 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
1926 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1928 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1929 break;
1932 else
1934 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1935 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1937 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1938 break;
1941 /* change to the current folder */
1942 nOpenAction = ONOPEN_OPEN;
1943 break;
1945 else
1947 nOpenAction = ONOPEN_OPEN;
1948 break;
1951 if(pidl) COMDLG32_SHFree(pidl);
1955 Step 3: here we have a cleaned up and validated path
1957 valid variables:
1958 lpsf: ShellFolder bound to the rightmost valid path component
1959 lpstrPathAndFile: cleaned up path
1960 nOpenAction: action to do
1962 TRACE("end validate sf=%p\n", lpsf);
1964 switch(nOpenAction)
1966 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1967 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1969 int iPos;
1970 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1971 DWORD len;
1973 /* replace the current filter */
1974 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
1975 len = lstrlenW(lpszTemp)+1;
1976 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1977 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1979 /* set the filter cb to the extension when possible */
1980 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1981 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1983 /* fall through */
1984 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1985 TRACE("ONOPEN_BROWSE\n");
1987 IPersistFolder2 * ppf2;
1988 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1990 LPITEMIDLIST pidlCurrent;
1991 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1992 IPersistFolder2_Release(ppf2);
1993 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1995 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE)))
1997 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2000 else if( nOpenAction == ONOPEN_SEARCH )
2002 if (fodInfos->Shell.FOIShellView)
2003 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2005 COMDLG32_SHFree(pidlCurrent);
2006 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2009 ret = FALSE;
2010 break;
2011 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2012 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2014 WCHAR *ext = NULL;
2016 /* update READONLY check box flag */
2017 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2018 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2019 else
2020 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2022 /* Attach the file extension with file name*/
2023 ext = PathFindExtensionW(lpstrPathAndFile);
2024 if (! *ext)
2026 /* if no extension is specified with file name, then */
2027 /* attach the extension from file filter or default one */
2029 WCHAR *filterExt = NULL;
2030 LPWSTR lpstrFilter = NULL;
2031 static const WCHAR szwDot[] = {'.',0};
2032 int PathLength = lstrlenW(lpstrPathAndFile);
2034 /* Attach the dot*/
2035 lstrcatW(lpstrPathAndFile, szwDot);
2037 /*Get the file extension from file type filter*/
2038 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2039 fodInfos->ofnInfos->nFilterIndex-1);
2041 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2042 filterExt = PathFindExtensionW(lpstrFilter);
2044 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2045 lstrcatW(lpstrPathAndFile, filterExt + 1);
2046 else if ( fodInfos->defext ) /* attach the default file extension*/
2047 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2049 /* In Open dialog: if file does not exist try without extension */
2050 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2051 lpstrPathAndFile[PathLength] = '\0';
2054 if (fodInfos->defext) /* add default extension */
2056 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2057 if (*ext)
2058 ext++;
2059 if (!lstrcmpiW(fodInfos->defext, ext))
2060 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2061 else
2062 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2065 /* In Save dialog: check if the file already exists */
2066 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2067 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2068 && PathFileExistsW(lpstrPathAndFile))
2070 WCHAR lpstrOverwrite[100];
2071 int answer;
2073 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2074 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2075 MB_YESNO | MB_ICONEXCLAMATION);
2076 if (answer == IDNO)
2078 ret = FALSE;
2079 goto ret;
2083 /* In Open dialog: check if it should be created if it doesn't exist */
2084 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2085 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2086 && !PathFileExistsW(lpstrPathAndFile))
2088 WCHAR lpstrCreate[100];
2089 int answer;
2091 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2092 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2093 MB_YESNO | MB_ICONEXCLAMATION);
2094 if (answer == IDNO)
2096 ret = FALSE;
2097 goto ret;
2101 /* Check that the size of the file does not exceed buffer size.
2102 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2103 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2104 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2107 /* fill destination buffer */
2108 if (fodInfos->ofnInfos->lpstrFile)
2110 if(fodInfos->unicode)
2112 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2114 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2115 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2116 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2118 else
2120 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2122 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2123 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2124 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2125 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2129 if(fodInfos->unicode)
2131 LPWSTR lpszTemp;
2133 /* set filename offset */
2134 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2135 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2137 /* set extension offset */
2138 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2139 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2141 else
2143 LPSTR lpszTemp;
2144 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2146 /* set filename offset */
2147 lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2148 fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2150 /* set extension offset */
2151 lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2152 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2155 /* set the lpstrFileTitle */
2156 if(fodInfos->ofnInfos->lpstrFileTitle)
2158 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2159 if(fodInfos->unicode)
2161 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2162 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2164 else
2166 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2167 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2168 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2172 /* copy currently selected filter to lpstrCustomFilter */
2173 if (fodInfos->ofnInfos->lpstrCustomFilter)
2175 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2176 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2177 NULL, 0, NULL, NULL);
2178 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2180 LPSTR s = ofn->lpstrCustomFilter;
2181 s += strlen(ofn->lpstrCustomFilter)+1;
2182 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2183 s, len, NULL, NULL);
2188 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2189 goto ret;
2191 TRACE("close\n");
2192 FILEDLG95_Clean(hwnd);
2193 ret = EndDialog(hwnd, TRUE);
2195 else
2197 WORD size;
2199 size = lstrlenW(lpstrPathAndFile) + 1;
2200 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2201 size += 1;
2202 /* return needed size in first two bytes of lpstrFile */
2203 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2204 FILEDLG95_Clean(hwnd);
2205 ret = EndDialog(hwnd, FALSE);
2206 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2209 break;
2212 ret:
2213 if(lpsf) IShellFolder_Release(lpsf);
2214 return ret;
2217 /***********************************************************************
2218 * FILEDLG95_SHELL_Init
2220 * Initialisation of the shell objects
2222 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2224 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2226 TRACE("\n");
2229 * Initialisation of the FileOpenDialogInfos structure
2232 /* Shell */
2234 /*ShellInfos */
2235 fodInfos->ShellInfos.hwndOwner = hwnd;
2237 /* Disable multi-select if flag not set */
2238 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2240 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2242 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2243 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2245 /* Construct the IShellBrowser interface */
2246 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2248 return NOERROR;
2251 /***********************************************************************
2252 * FILEDLG95_SHELL_ExecuteCommand
2254 * Change the folder option and refresh the view
2255 * If the function succeeds, the return value is nonzero.
2257 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2259 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2260 IContextMenu * pcm;
2262 TRACE("(%p,%p)\n", hwnd, lpVerb);
2264 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2265 SVGIO_BACKGROUND,
2266 &IID_IContextMenu,
2267 (LPVOID*)&pcm)))
2269 CMINVOKECOMMANDINFO ci;
2270 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2271 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2272 ci.lpVerb = lpVerb;
2273 ci.hwnd = hwnd;
2275 IContextMenu_InvokeCommand(pcm, &ci);
2276 IContextMenu_Release(pcm);
2279 return FALSE;
2282 /***********************************************************************
2283 * FILEDLG95_SHELL_UpFolder
2285 * Browse to the specified object
2286 * If the function succeeds, the return value is nonzero.
2288 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2290 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2292 TRACE("\n");
2294 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2295 NULL,
2296 SBSP_PARENT)))
2298 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2299 return TRUE;
2301 return FALSE;
2304 /***********************************************************************
2305 * FILEDLG95_SHELL_BrowseToDesktop
2307 * Browse to the Desktop
2308 * If the function succeeds, the return value is nonzero.
2310 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2312 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2313 LPITEMIDLIST pidl;
2314 HRESULT hres;
2316 TRACE("\n");
2318 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2319 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2320 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2321 COMDLG32_SHFree(pidl);
2322 return SUCCEEDED(hres);
2324 /***********************************************************************
2325 * FILEDLG95_SHELL_Clean
2327 * Cleans the memory used by shell objects
2329 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2331 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2333 TRACE("\n");
2335 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2337 /* clean Shell interfaces */
2338 if (fodInfos->Shell.FOIShellView)
2340 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2341 IShellView_Release(fodInfos->Shell.FOIShellView);
2343 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2344 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2345 if (fodInfos->Shell.FOIDataObject)
2346 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2349 /***********************************************************************
2350 * FILEDLG95_FILETYPE_Init
2352 * Initialisation of the file type combo box
2354 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2356 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2357 int nFilters = 0; /* number of filters */
2358 int nFilterIndexCB;
2360 TRACE("\n");
2362 if(fodInfos->customfilter)
2364 /* customfilter has one entry... title\0ext\0
2365 * Set first entry of combo box item with customfilter
2367 LPWSTR lpstrExt;
2368 LPCWSTR lpstrPos = fodInfos->customfilter;
2370 /* Get the title */
2371 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2373 /* Copy the extensions */
2374 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2375 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2376 lstrcpyW(lpstrExt,lpstrPos);
2378 /* Add the item at the end of the combo */
2379 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2380 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2381 nFilters++;
2383 if(fodInfos->filter)
2385 LPCWSTR lpstrPos = fodInfos->filter;
2387 for(;;)
2389 /* filter is a list... title\0ext\0......\0\0
2390 * Set the combo item text to the title and the item data
2391 * to the ext
2393 LPCWSTR lpstrDisplay;
2394 LPWSTR lpstrExt;
2396 /* Get the title */
2397 if(! *lpstrPos) break; /* end */
2398 lpstrDisplay = lpstrPos;
2399 lpstrPos += lstrlenW(lpstrPos) + 1;
2401 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2403 nFilters++;
2405 /* Copy the extensions */
2406 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2407 lstrcpyW(lpstrExt,lpstrPos);
2408 lpstrPos += lstrlenW(lpstrPos) + 1;
2410 /* Add the item at the end of the combo */
2411 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2413 /* malformed filters are added anyway... */
2414 if (!*lpstrExt) break;
2419 * Set the current filter to the one specified
2420 * in the initialisation structure
2422 if (fodInfos->filter || fodInfos->customfilter)
2424 LPWSTR lpstrFilter;
2426 /* Check to make sure our index isn't out of bounds. */
2427 if ( fodInfos->ofnInfos->nFilterIndex >
2428 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2429 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2431 /* set default filter index */
2432 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2433 fodInfos->ofnInfos->nFilterIndex = 1;
2435 /* calculate index of Combo Box item */
2436 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2437 if (fodInfos->customfilter == NULL)
2438 nFilterIndexCB--;
2440 /* Set the current index selection. */
2441 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2443 /* Get the corresponding text string from the combo box. */
2444 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2445 nFilterIndexCB);
2447 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2448 lpstrFilter = NULL;
2450 if(lpstrFilter)
2452 DWORD len;
2453 CharLowerW(lpstrFilter); /* lowercase */
2454 len = lstrlenW(lpstrFilter)+1;
2455 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2456 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2458 } else
2459 fodInfos->ofnInfos->nFilterIndex = 0;
2460 return S_OK;
2463 /***********************************************************************
2464 * FILEDLG95_FILETYPE_OnCommand
2466 * WM_COMMAND of the file type combo box
2467 * If the function succeeds, the return value is nonzero.
2469 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2471 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2473 switch(wNotifyCode)
2475 case CBN_SELENDOK:
2477 LPWSTR lpstrFilter;
2479 /* Get the current item of the filetype combo box */
2480 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2482 /* set the current filter index */
2483 fodInfos->ofnInfos->nFilterIndex = iItem +
2484 (fodInfos->customfilter == NULL ? 1 : 0);
2486 /* Set the current filter with the current selection */
2487 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2489 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2490 iItem);
2491 if((INT_PTR)lpstrFilter != CB_ERR)
2493 DWORD len;
2494 CharLowerW(lpstrFilter); /* lowercase */
2495 len = lstrlenW(lpstrFilter)+1;
2496 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2497 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2498 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2501 /* Refresh the actual view to display the included items*/
2502 if (fodInfos->Shell.FOIShellView)
2503 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2506 return FALSE;
2508 /***********************************************************************
2509 * FILEDLG95_FILETYPE_SearchExt
2511 * searches for an extension in the filetype box
2513 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2515 int i, iCount = CBGetCount(hwnd);
2517 TRACE("%s\n", debugstr_w(lpstrExt));
2519 if(iCount != CB_ERR)
2521 for(i=0;i<iCount;i++)
2523 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2524 return i;
2527 return -1;
2530 /***********************************************************************
2531 * FILEDLG95_FILETYPE_Clean
2533 * Clean the memory used by the filetype combo box
2535 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2537 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2538 int iPos;
2539 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2541 TRACE("\n");
2543 /* Delete each string of the combo and their associated data */
2544 if(iCount != CB_ERR)
2546 for(iPos = iCount-1;iPos>=0;iPos--)
2548 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2549 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2552 /* Current filter */
2553 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2557 /***********************************************************************
2558 * FILEDLG95_LOOKIN_Init
2560 * Initialisation of the look in combo box
2563 /* Small helper function, to determine if the unixfs shell extension is rooted
2564 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2566 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2567 HKEY hKey;
2568 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2569 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2570 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2571 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2572 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2573 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2574 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2576 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2577 return FALSE;
2579 RegCloseKey(hKey);
2580 return TRUE;
2583 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2585 IShellFolder *psfRoot, *psfDrives;
2586 IEnumIDList *lpeRoot, *lpeDrives;
2587 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2589 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2591 TRACE("\n");
2593 liInfos->iMaxIndentation = 0;
2595 SetPropA(hwndCombo, LookInInfosStr, liInfos);
2597 /* set item height for both text field and listbox */
2598 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2599 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2601 /* Turn on the extended UI for the combo box like Windows does */
2602 CBSetExtendedUI(hwndCombo, TRUE);
2604 /* Initialise data of Desktop folder */
2605 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2606 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2607 COMDLG32_SHFree(pidlTmp);
2609 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2611 SHGetDesktopFolder(&psfRoot);
2613 if (psfRoot)
2615 /* enumerate the contents of the desktop */
2616 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2618 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2620 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2622 /* If the unixfs extension is rooted, we don't expand the drives by default */
2623 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2625 /* special handling for CSIDL_DRIVES */
2626 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2628 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2630 /* enumerate the drives */
2631 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2633 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2635 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2636 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2637 COMDLG32_SHFree(pidlAbsTmp);
2638 COMDLG32_SHFree(pidlTmp1);
2640 IEnumIDList_Release(lpeDrives);
2642 IShellFolder_Release(psfDrives);
2647 COMDLG32_SHFree(pidlTmp);
2649 IEnumIDList_Release(lpeRoot);
2651 IShellFolder_Release(psfRoot);
2654 COMDLG32_SHFree(pidlDrives);
2657 /***********************************************************************
2658 * FILEDLG95_LOOKIN_DrawItem
2660 * WM_DRAWITEM message handler
2662 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2664 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2665 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2666 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2667 RECT rectText;
2668 RECT rectIcon;
2669 SHFILEINFOW sfi;
2670 HIMAGELIST ilItemImage;
2671 int iIndentation;
2672 TEXTMETRICW tm;
2673 LPSFOLDER tmpFolder;
2674 LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2676 TRACE("\n");
2678 if(pDIStruct->itemID == -1)
2679 return 0;
2681 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2682 pDIStruct->itemID)))
2683 return 0;
2686 if(pDIStruct->itemID == liInfos->uSelectedItem)
2688 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2690 &sfi,
2691 sizeof (sfi),
2692 SHGFI_PIDL | SHGFI_SMALLICON |
2693 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2694 SHGFI_DISPLAYNAME );
2696 else
2698 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2700 &sfi,
2701 sizeof (sfi),
2702 SHGFI_PIDL | SHGFI_SMALLICON |
2703 SHGFI_SYSICONINDEX |
2704 SHGFI_DISPLAYNAME);
2707 /* Is this item selected ? */
2708 if(pDIStruct->itemState & ODS_SELECTED)
2710 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2711 SetBkColor(pDIStruct->hDC,crHighLight);
2712 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2714 else
2716 SetTextColor(pDIStruct->hDC,crText);
2717 SetBkColor(pDIStruct->hDC,crWin);
2718 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2721 /* Do not indent item if drawing in the edit of the combo */
2722 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2724 iIndentation = 0;
2725 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2727 &sfi,
2728 sizeof (sfi),
2729 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2730 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2733 else
2735 iIndentation = tmpFolder->m_iIndent;
2737 /* Draw text and icon */
2739 /* Initialise the icon display area */
2740 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2741 rectIcon.top = pDIStruct->rcItem.top;
2742 rectIcon.right = rectIcon.left + ICONWIDTH;
2743 rectIcon.bottom = pDIStruct->rcItem.bottom;
2745 /* Initialise the text display area */
2746 GetTextMetricsW(pDIStruct->hDC, &tm);
2747 rectText.left = rectIcon.right;
2748 rectText.top =
2749 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2750 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2751 rectText.bottom =
2752 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2754 /* Draw the icon from the image list */
2755 ImageList_Draw(ilItemImage,
2756 sfi.iIcon,
2757 pDIStruct->hDC,
2758 rectIcon.left,
2759 rectIcon.top,
2760 ILD_TRANSPARENT );
2762 /* Draw the associated text */
2763 if(sfi.szDisplayName)
2764 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
2767 return NOERROR;
2770 /***********************************************************************
2771 * FILEDLG95_LOOKIN_OnCommand
2773 * LookIn combo box WM_COMMAND message handler
2774 * If the function succeeds, the return value is nonzero.
2776 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2778 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2780 TRACE("%p\n", fodInfos);
2782 switch(wNotifyCode)
2784 case CBN_SELENDOK:
2786 LPSFOLDER tmpFolder;
2787 int iItem;
2789 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2791 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2792 iItem)))
2793 return FALSE;
2796 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2797 tmpFolder->pidlItem,
2798 SBSP_ABSOLUTE)))
2800 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2801 return TRUE;
2803 break;
2807 return FALSE;
2810 /***********************************************************************
2811 * FILEDLG95_LOOKIN_AddItem
2813 * Adds an absolute pidl item to the lookin combo box
2814 * returns the index of the inserted item
2816 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2818 LPITEMIDLIST pidlNext;
2819 SHFILEINFOW sfi;
2820 SFOLDER *tmpFolder;
2821 LookInInfos *liInfos;
2823 TRACE("%08x\n", iInsertId);
2825 if(!pidl)
2826 return -1;
2828 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
2829 return -1;
2831 tmpFolder = MemAlloc(sizeof(SFOLDER));
2832 tmpFolder->m_iIndent = 0;
2834 /* Calculate the indentation of the item in the lookin*/
2835 pidlNext = pidl;
2836 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2838 tmpFolder->m_iIndent++;
2841 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2843 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2844 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2846 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2847 SHGetFileInfoW((LPCWSTR)pidl,
2849 &sfi,
2850 sizeof(sfi),
2851 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2852 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2854 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
2856 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2858 int iItemID;
2860 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
2862 /* Add the item at the end of the list */
2863 if(iInsertId < 0)
2865 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2867 /* Insert the item at the iInsertId position*/
2868 else
2870 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2873 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2874 return iItemID;
2877 COMDLG32_SHFree( tmpFolder->pidlItem );
2878 MemFree( tmpFolder );
2879 return -1;
2883 /***********************************************************************
2884 * FILEDLG95_LOOKIN_InsertItemAfterParent
2886 * Insert an item below its parent
2888 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2891 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2892 int iParentPos;
2894 TRACE("\n");
2896 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2898 if(iParentPos < 0)
2900 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2903 /* Free pidlParent memory */
2904 COMDLG32_SHFree(pidlParent);
2906 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2909 /***********************************************************************
2910 * FILEDLG95_LOOKIN_SelectItem
2912 * Adds an absolute pidl item to the lookin combo box
2913 * returns the index of the inserted item
2915 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2917 int iItemPos;
2918 LookInInfos *liInfos;
2920 TRACE("\n");
2922 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2924 liInfos = GetPropA(hwnd,LookInInfosStr);
2926 if(iItemPos < 0)
2928 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2929 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2932 else
2934 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2935 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2937 int iRemovedItem;
2939 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2940 break;
2941 if(iRemovedItem < iItemPos)
2942 iItemPos--;
2946 CBSetCurSel(hwnd,iItemPos);
2947 liInfos->uSelectedItem = iItemPos;
2949 return 0;
2953 /***********************************************************************
2954 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2956 * Remove the item with an expansion level over iExpansionLevel
2958 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2960 int iItemPos;
2961 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
2963 TRACE("\n");
2965 if(liInfos->iMaxIndentation <= 2)
2966 return -1;
2968 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2970 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2971 COMDLG32_SHFree(tmpFolder->pidlItem);
2972 MemFree(tmpFolder);
2973 CBDeleteString(hwnd,iItemPos);
2974 liInfos->iMaxIndentation--;
2976 return iItemPos;
2979 return -1;
2982 /***********************************************************************
2983 * FILEDLG95_LOOKIN_SearchItem
2985 * Search for pidl in the lookin combo box
2986 * returns the index of the found item
2988 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2990 int i = 0;
2991 int iCount = CBGetCount(hwnd);
2993 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
2995 if (iCount != CB_ERR)
2997 for(;i<iCount;i++)
2999 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3001 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3002 return i;
3003 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3004 return i;
3008 return -1;
3011 /***********************************************************************
3012 * FILEDLG95_LOOKIN_Clean
3014 * Clean the memory used by the lookin combo box
3016 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3018 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3019 int iPos;
3020 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3022 TRACE("\n");
3024 /* Delete each string of the combo and their associated data */
3025 if (iCount != CB_ERR)
3027 for(iPos = iCount-1;iPos>=0;iPos--)
3029 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3030 COMDLG32_SHFree(tmpFolder->pidlItem);
3031 MemFree(tmpFolder);
3032 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3036 /* LookInInfos structure */
3037 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3040 /***********************************************************************
3041 * FILEDLG95_FILENAME_FillFromSelection
3043 * fills the edit box from the cached DataObject
3045 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3047 FileOpenDlgInfos *fodInfos;
3048 LPITEMIDLIST pidl;
3049 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3050 WCHAR lpstrTemp[MAX_PATH];
3051 LPWSTR lpstrAllFile, lpstrCurrFile;
3053 TRACE("\n");
3054 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3056 /* Count how many files we have */
3057 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3059 /* calculate the string length, count files */
3060 if (nFileSelected >= 1)
3062 nLength += 3; /* first and last quotes, trailing \0 */
3063 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3065 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3067 if (pidl)
3069 /* get the total length of the selected file names */
3070 lpstrTemp[0] = '\0';
3071 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3073 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3075 nLength += lstrlenW( lpstrTemp ) + 3;
3076 nFiles++;
3078 COMDLG32_SHFree( pidl );
3083 /* allocate the buffer */
3084 if (nFiles <= 1) nLength = MAX_PATH;
3085 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3087 /* Generate the string for the edit control */
3088 if(nFiles >= 1)
3090 lpstrCurrFile = lpstrAllFile;
3091 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3093 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3095 if (pidl)
3097 /* get the file name */
3098 lpstrTemp[0] = '\0';
3099 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3101 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3103 if ( nFiles > 1)
3105 *lpstrCurrFile++ = '\"';
3106 lstrcpyW( lpstrCurrFile, lpstrTemp );
3107 lpstrCurrFile += lstrlenW( lpstrTemp );
3108 *lpstrCurrFile++ = '\"';
3109 *lpstrCurrFile++ = ' ';
3110 *lpstrCurrFile = 0;
3112 else
3114 lstrcpyW( lpstrAllFile, lpstrTemp );
3117 COMDLG32_SHFree( pidl );
3120 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3122 /* Select the file name like Windows does */
3123 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3125 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3129 /* copied from shell32 to avoid linking to it
3130 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3131 * is dependent on whether emulated OS is unicode or not.
3133 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3135 switch (src->uType)
3137 case STRRET_WSTR:
3138 lstrcpynW(dest, src->u.pOleStr, len);
3139 COMDLG32_SHFree(src->u.pOleStr);
3140 break;
3142 case STRRET_CSTR:
3143 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3144 dest[len-1] = 0;
3145 break;
3147 case STRRET_OFFSET:
3148 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3149 dest[len-1] = 0;
3150 break;
3152 default:
3153 FIXME("unknown type %x!\n", src->uType);
3154 if (len) *dest = '\0';
3155 return E_FAIL;
3157 return S_OK;
3160 /***********************************************************************
3161 * FILEDLG95_FILENAME_GetFileNames
3163 * Copies the filenames to a delimited string list.
3164 * The delimiter is specified by the parameter 'separator',
3165 * usually either a space or a nul
3167 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3169 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3170 UINT nStrCharCount = 0; /* index in src buffer */
3171 UINT nFileIndex = 0; /* index in dest buffer */
3172 UINT nFileCount = 0; /* number of files */
3173 UINT nStrLen = 0; /* length of string in edit control */
3174 LPWSTR lpstrEdit; /* buffer for string from edit control */
3176 TRACE("\n");
3178 /* get the filenames from the edit control */
3179 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3180 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3181 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3183 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3185 /* we might get single filename without any '"',
3186 * so we need nStrLen + terminating \0 + end-of-list \0 */
3187 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3188 *sizeUsed = 0;
3190 /* build delimited file list from filenames */
3191 while ( nStrCharCount <= nStrLen )
3193 if ( lpstrEdit[nStrCharCount]=='"' )
3195 nStrCharCount++;
3196 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3198 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3199 nStrCharCount++;
3201 (*lpstrFileList)[nFileIndex++] = 0;
3202 nFileCount++;
3204 nStrCharCount++;
3207 /* single, unquoted string */
3208 if ((nStrLen > 0) && (nFileIndex == 0) )
3210 lstrcpyW(*lpstrFileList, lpstrEdit);
3211 nFileIndex = lstrlenW(lpstrEdit) + 1;
3212 nFileCount = 1;
3215 /* trailing \0 */
3216 (*lpstrFileList)[nFileIndex++] = '\0';
3218 *sizeUsed = nFileIndex;
3219 MemFree(lpstrEdit);
3220 return nFileCount;
3223 #define SETDefFormatEtc(fe,cf,med) \
3225 (fe).cfFormat = cf;\
3226 (fe).dwAspect = DVASPECT_CONTENT; \
3227 (fe).ptd =NULL;\
3228 (fe).tymed = med;\
3229 (fe).lindex = -1;\
3233 * DATAOBJECT Helper functions
3236 /***********************************************************************
3237 * COMCTL32_ReleaseStgMedium
3239 * like ReleaseStgMedium from ole32
3241 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3243 if(medium.pUnkForRelease)
3245 IUnknown_Release(medium.pUnkForRelease);
3247 else
3249 GlobalUnlock(medium.u.hGlobal);
3250 GlobalFree(medium.u.hGlobal);
3254 /***********************************************************************
3255 * GetPidlFromDataObject
3257 * Return pidl(s) by number from the cached DataObject
3259 * nPidlIndex=0 gets the fully qualified root path
3261 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3264 STGMEDIUM medium;
3265 FORMATETC formatetc;
3266 LPITEMIDLIST pidl = NULL;
3268 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3270 if (!doSelected)
3271 return NULL;
3273 /* Set the FORMATETC structure*/
3274 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3276 /* Get the pidls from IDataObject */
3277 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3279 LPIDA cida = GlobalLock(medium.u.hGlobal);
3280 if(nPidlIndex <= cida->cidl)
3282 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3284 COMCTL32_ReleaseStgMedium(medium);
3286 return pidl;
3289 /***********************************************************************
3290 * GetNumSelected
3292 * Return the number of selected items in the DataObject.
3295 static UINT GetNumSelected( IDataObject *doSelected )
3297 UINT retVal = 0;
3298 STGMEDIUM medium;
3299 FORMATETC formatetc;
3301 TRACE("sv=%p\n", doSelected);
3303 if (!doSelected) return 0;
3305 /* Set the FORMATETC structure*/
3306 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3308 /* Get the pidls from IDataObject */
3309 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3311 LPIDA cida = GlobalLock(medium.u.hGlobal);
3312 retVal = cida->cidl;
3313 COMCTL32_ReleaseStgMedium(medium);
3314 return retVal;
3316 return 0;
3320 * TOOLS
3323 /***********************************************************************
3324 * GetName
3326 * Get the pidl's display name (relative to folder) and
3327 * put it in lpstrFileName.
3329 * Return NOERROR on success,
3330 * E_FAIL otherwise
3333 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3335 STRRET str;
3336 HRESULT hRes;
3338 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3340 if(!lpsf)
3342 SHGetDesktopFolder(&lpsf);
3343 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3344 IShellFolder_Release(lpsf);
3345 return hRes;
3348 /* Get the display name of the pidl relative to the folder */
3349 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3351 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3353 return E_FAIL;
3356 /***********************************************************************
3357 * GetShellFolderFromPidl
3359 * pidlRel is the item pidl relative
3360 * Return the IShellFolder of the absolute pidl
3362 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3364 IShellFolder *psf = NULL,*psfParent;
3366 TRACE("%p\n", pidlAbs);
3368 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3370 psf = psfParent;
3371 if(pidlAbs && pidlAbs->mkid.cb)
3373 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3375 IShellFolder_Release(psfParent);
3376 return psf;
3379 /* return the desktop */
3380 return psfParent;
3382 return NULL;
3385 /***********************************************************************
3386 * GetParentPidl
3388 * Return the LPITEMIDLIST to the parent of the pidl in the list
3390 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3392 LPITEMIDLIST pidlParent;
3394 TRACE("%p\n", pidl);
3396 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3397 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3399 return pidlParent;
3402 /***********************************************************************
3403 * GetPidlFromName
3405 * returns the pidl of the file name relative to folder
3406 * NULL if an error occurred
3408 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3410 LPITEMIDLIST pidl = NULL;
3411 ULONG ulEaten;
3413 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3415 if(!lpcstrFileName) return NULL;
3416 if(!*lpcstrFileName) return NULL;
3418 if(!lpsf)
3420 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3421 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3422 IShellFolder_Release(lpsf);
3425 else
3427 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3429 return pidl;
3434 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3436 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3437 HRESULT ret;
3439 TRACE("%p, %p\n", psf, pidl);
3441 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3443 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3444 /* see documentation shell 4.1*/
3445 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3448 /***********************************************************************
3449 * BrowseSelectedFolder
3451 static BOOL BrowseSelectedFolder(HWND hwnd)
3453 BOOL bBrowseSelFolder = FALSE;
3454 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3456 TRACE("\n");
3458 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3460 LPITEMIDLIST pidlSelection;
3462 /* get the file selected */
3463 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3464 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3466 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3467 pidlSelection, SBSP_RELATIVE ) ) )
3469 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3470 ' ','n','o','t',' ','e','x','i','s','t',0};
3471 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3473 bBrowseSelFolder = TRUE;
3474 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3476 COMDLG32_SHFree( pidlSelection );
3479 return bBrowseSelFolder;
3483 * Memory allocation methods */
3484 static void *MemAlloc(UINT size)
3486 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3489 static void MemFree(void *mem)
3491 HeapFree(GetProcessHeap(),0,mem);
3495 * Old-style (win3.1) dialogs */
3497 /***********************************************************************
3498 * FD32_GetTemplate [internal]
3500 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3501 * by a 32 bits application
3504 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3506 LPOPENFILENAMEW ofnW = lfs->ofnW;
3507 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3508 HANDLE hDlgTmpl;
3510 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3512 if (!(lfs->template = LockResource( ofnW->hInstance )))
3514 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3515 return FALSE;
3518 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3520 HRSRC hResInfo;
3521 if (priv->ofnA)
3522 hResInfo = FindResourceA(priv->ofnA->hInstance,
3523 priv->ofnA->lpTemplateName,
3524 (LPSTR)RT_DIALOG);
3525 else
3526 hResInfo = FindResourceW(ofnW->hInstance,
3527 ofnW->lpTemplateName,
3528 (LPWSTR)RT_DIALOG);
3529 if (!hResInfo)
3531 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3532 return FALSE;
3534 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3535 hResInfo)) ||
3536 !(lfs->template = LockResource(hDlgTmpl)))
3538 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3539 return FALSE;
3541 } else { /* get it from internal Wine resource */
3542 HRSRC hResInfo;
3543 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3544 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3546 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3547 return FALSE;
3549 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3550 !(lfs->template = LockResource( hDlgTmpl )))
3552 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3553 return FALSE;
3556 return TRUE;
3560 /************************************************************************
3561 * FD32_Init [internal]
3562 * called from the common 16/32 code to initialize 32 bit data
3564 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3566 BOOL IsUnicode = (BOOL) data;
3567 PFD32_PRIVATE priv;
3569 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3570 lfs->private1632 = priv;
3571 if (NULL == lfs->private1632) return FALSE;
3572 if (IsUnicode)
3574 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3575 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3576 if (lfs->ofnW->lpfnHook)
3577 lfs->hook = TRUE;
3579 else
3581 priv->ofnA = (LPOPENFILENAMEA) lParam;
3582 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3583 if (priv->ofnA->lpfnHook)
3584 lfs->hook = TRUE;
3585 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3586 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3589 if (! FD32_GetTemplate(lfs)) return FALSE;
3591 return TRUE;
3594 /***********************************************************************
3595 * FD32_CallWindowProc [internal]
3597 * called from the common 16/32 code to call the appropriate hook
3599 static BOOL CALLBACK FD32_CallWindowProc(const FD31_DATA *lfs, UINT wMsg, WPARAM wParam,
3600 LPARAM lParam)
3602 BOOL ret;
3603 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3605 if (priv->ofnA)
3607 TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3608 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3609 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3610 TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3611 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3612 return ret;
3615 TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3616 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3617 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3618 TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3619 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3620 return ret;
3623 /***********************************************************************
3624 * FD32_UpdateResult [internal]
3625 * update the real client structures if any
3627 static void CALLBACK FD32_UpdateResult(const FD31_DATA *lfs)
3629 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3630 LPOPENFILENAMEW ofnW = lfs->ofnW;
3632 if (priv->ofnA)
3634 LPSTR lpszTemp;
3635 if (ofnW->nMaxFile &&
3636 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3637 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3638 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3640 /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
3641 /* set filename offset */
3642 lpszTemp = PathFindFileNameA(priv->ofnA->lpstrFile);
3643 priv->ofnA->nFileOffset = (lpszTemp - priv->ofnA->lpstrFile);
3645 /* set extension offset */
3646 lpszTemp = PathFindExtensionA(priv->ofnA->lpstrFile);
3647 priv->ofnA->nFileExtension = (*lpszTemp) ? (lpszTemp - priv->ofnA->lpstrFile) + 1 : 0;
3651 /***********************************************************************
3652 * FD32_UpdateFileTitle [internal]
3653 * update the real client structures if any
3655 static void CALLBACK FD32_UpdateFileTitle(const FD31_DATA *lfs)
3657 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3658 LPOPENFILENAMEW ofnW = lfs->ofnW;
3660 if (priv->ofnA)
3662 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3663 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3664 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3669 /***********************************************************************
3670 * FD32_SendLbGetCurSel [internal]
3671 * retrieve selected listbox item
3673 static LRESULT CALLBACK FD32_SendLbGetCurSel(const FD31_DATA *lfs)
3675 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3679 /************************************************************************
3680 * FD32_Destroy [internal]
3681 * called from the common 16/32 code to cleanup 32 bit data
3683 static void CALLBACK FD32_Destroy(const FD31_DATA *lfs)
3685 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3687 /* if ofnW has been allocated, have to free everything in it */
3688 if (NULL != priv && NULL != priv->ofnA)
3690 FD31_FreeOfnW(lfs->ofnW);
3691 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3695 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3697 callbacks->Init = FD32_Init;
3698 callbacks->CWP = FD32_CallWindowProc;
3699 callbacks->UpdateResult = FD32_UpdateResult;
3700 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3701 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3702 callbacks->Destroy = FD32_Destroy;
3705 /***********************************************************************
3706 * FD32_WMMeasureItem [internal]
3708 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3710 LPMEASUREITEMSTRUCT lpmeasure;
3712 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3713 lpmeasure->itemHeight = FD31_GetFldrHeight();
3714 return TRUE;
3718 /***********************************************************************
3719 * FileOpenDlgProc [internal]
3720 * Used for open and save, in fact.
3722 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3723 WPARAM wParam, LPARAM lParam)
3725 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3727 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
3728 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3730 INT_PTR lRet;
3731 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3732 if (lRet)
3733 return lRet; /* else continue message processing */
3735 switch (wMsg)
3737 case WM_INITDIALOG:
3738 return FD31_WMInitDialog(hWnd, wParam, lParam);
3740 case WM_MEASUREITEM:
3741 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3743 case WM_DRAWITEM:
3744 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3746 case WM_COMMAND:
3747 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3748 #if 0
3749 case WM_CTLCOLOR:
3750 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3751 switch (HIWORD(lParam))
3753 case CTLCOLOR_BTN:
3754 SetTextColor((HDC16)wParam, 0x00000000);
3755 return hGRAYBrush;
3756 case CTLCOLOR_STATIC:
3757 SetTextColor((HDC16)wParam, 0x00000000);
3758 return hGRAYBrush;
3760 break;
3761 #endif
3763 return FALSE;
3767 /***********************************************************************
3768 * GetFileName31A [internal]
3770 * Creates a win31 style dialog box for the user to select a file to open/save.
3772 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
3773 UINT dlgType /* type dialogue : open/save */
3776 HINSTANCE hInst;
3777 BOOL bRet = FALSE;
3778 PFD31_DATA lfs;
3779 FD31_CALLBACKS callbacks;
3781 if (!lpofn || !FD31_Init()) return FALSE;
3783 TRACE("ofn flags %08x\n", lpofn->Flags);
3784 FD32_SetupCallbacks(&callbacks);
3785 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3786 if (lfs)
3788 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3789 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3790 FD32_FileOpenDlgProc, (LPARAM)lfs);
3791 FD31_DestroyPrivate(lfs);
3794 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3795 return bRet;
3798 /***********************************************************************
3799 * GetFileName31W [internal]
3801 * Creates a win31 style dialog box for the user to select a file to open/save
3803 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
3804 UINT dlgType /* type dialogue : open/save */
3807 HINSTANCE hInst;
3808 BOOL bRet = FALSE;
3809 PFD31_DATA lfs;
3810 FD31_CALLBACKS callbacks;
3812 if (!lpofn || !FD31_Init()) return FALSE;
3814 FD32_SetupCallbacks(&callbacks);
3815 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3816 if (lfs)
3818 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3819 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3820 FD32_FileOpenDlgProc, (LPARAM)lfs);
3821 FD31_DestroyPrivate(lfs);
3824 TRACE("file %s, file offset %d, ext offset %d\n",
3825 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3826 return bRet;
3829 /* ------------------ APIs ---------------------- */
3831 /***********************************************************************
3832 * GetOpenFileNameA (COMDLG32.@)
3834 * Creates a dialog box for the user to select a file to open.
3836 * RETURNS
3837 * TRUE on success: user enters a valid file
3838 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3841 BOOL WINAPI GetOpenFileNameA(
3842 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3844 BOOL win16look = FALSE;
3846 TRACE("flags %08x\n", ofn->Flags);
3848 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3849 if (ofn->Flags & OFN_FILEMUSTEXIST)
3850 ofn->Flags |= OFN_PATHMUSTEXIST;
3852 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3853 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3855 if (win16look)
3856 return GetFileName31A(ofn, OPEN_DIALOG);
3857 else
3858 return GetFileDialog95A(ofn, OPEN_DIALOG);
3861 /***********************************************************************
3862 * GetOpenFileNameW (COMDLG32.@)
3864 * Creates a dialog box for the user to select a file to open.
3866 * RETURNS
3867 * TRUE on success: user enters a valid file
3868 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3871 BOOL WINAPI GetOpenFileNameW(
3872 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3874 BOOL win16look = FALSE;
3876 TRACE("flags %08x\n", ofn->Flags);
3878 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3879 if (ofn->Flags & OFN_FILEMUSTEXIST)
3880 ofn->Flags |= OFN_PATHMUSTEXIST;
3882 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3883 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3885 if (win16look)
3886 return GetFileName31W(ofn, OPEN_DIALOG);
3887 else
3888 return GetFileDialog95W(ofn, OPEN_DIALOG);
3892 /***********************************************************************
3893 * GetSaveFileNameA (COMDLG32.@)
3895 * Creates a dialog box for the user to select a file to save.
3897 * RETURNS
3898 * TRUE on success: user enters a valid file
3899 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3902 BOOL WINAPI GetSaveFileNameA(
3903 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3905 BOOL win16look = FALSE;
3907 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3908 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3910 if (win16look)
3911 return GetFileName31A(ofn, SAVE_DIALOG);
3912 else
3913 return GetFileDialog95A(ofn, SAVE_DIALOG);
3916 /***********************************************************************
3917 * GetSaveFileNameW (COMDLG32.@)
3919 * Creates a dialog box for the user to select a file to save.
3921 * RETURNS
3922 * TRUE on success: user enters a valid file
3923 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3926 BOOL WINAPI GetSaveFileNameW(
3927 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3929 BOOL win16look = FALSE;
3931 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3932 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3934 if (win16look)
3935 return GetFileName31W(ofn, SAVE_DIALOG);
3936 else
3937 return GetFileDialog95W(ofn, SAVE_DIALOG);
3940 /***********************************************************************
3941 * GetFileTitleA (COMDLG32.@)
3943 * See GetFileTitleW.
3945 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
3947 int ret;
3948 UNICODE_STRING strWFile;
3949 LPWSTR lpWTitle;
3951 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
3952 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
3953 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
3954 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
3955 RtlFreeUnicodeString( &strWFile );
3956 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
3957 return ret;
3961 /***********************************************************************
3962 * GetFileTitleW (COMDLG32.@)
3964 * Get the name of a file.
3966 * PARAMS
3967 * lpFile [I] name and location of file
3968 * lpTitle [O] returned file name
3969 * cbBuf [I] buffer size of lpTitle
3971 * RETURNS
3972 * Success: zero
3973 * Failure: negative number.
3975 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
3977 int i, len;
3978 static const WCHAR brkpoint[] = {'*','[',']',0};
3979 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
3981 if(lpFile == NULL || lpTitle == NULL)
3982 return -1;
3984 len = lstrlenW(lpFile);
3986 if (len == 0)
3987 return -1;
3989 if(strpbrkW(lpFile, brkpoint))
3990 return -1;
3992 len--;
3994 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
3995 return -1;
3997 for(i = len; i >= 0; i--)
3999 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4001 i++;
4002 break;
4006 if(i == -1)
4007 i++;
4009 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4011 len = lstrlenW(lpFile+i)+1;
4012 if(cbBuf < len)
4013 return len;
4015 lstrcpyW(lpTitle, &lpFile[i]);
4016 return 0;