shell32/tests: Fixed potential overflow.
[wine/gsoc_dplay.git] / dlls / comdlg32 / filedlg.c
blob73c9043a8e81aad1ff9806398cca7f28dbe7e6d7
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_CREATEPROMPT, OFN_DONTADDTORECENT,
40 * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING,
41 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
42 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
44 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
49 #include "config.h"
50 #include "wine/port.h"
52 #include <ctype.h>
53 #include <stdlib.h>
54 #include <stdarg.h>
55 #include <stdio.h>
56 #include <string.h>
58 #define COBJMACROS
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
62 #include "windef.h"
63 #include "winbase.h"
64 #include "winreg.h"
65 #include "winternl.h"
66 #include "winnls.h"
67 #include "wine/unicode.h"
68 #include "wingdi.h"
69 #include "winuser.h"
70 #include "winreg.h"
71 #include "commdlg.h"
72 #include "dlgs.h"
73 #include "cdlg.h"
74 #include "filedlg31.h"
75 #include "wine/debug.h"
76 #include "cderr.h"
77 #include "shellapi.h"
78 #include "shlguid.h"
79 #include "shlobj.h"
80 #include "filedlgbrowser.h"
81 #include "shlwapi.h"
83 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
85 #define UNIMPLEMENTED_FLAGS \
86 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
87 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
88 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
89 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
91 #define IsHooked(fodInfos) \
92 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
93 /***********************************************************************
94 * Data structure and global variables
96 typedef struct SFolder
98 int m_iImageIndex; /* Index of picture in image list */
99 HIMAGELIST hImgList;
100 int m_iIndent; /* Indentation index */
101 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
103 } SFOLDER,*LPSFOLDER;
105 typedef struct tagLookInInfo
107 int iMaxIndentation;
108 UINT uSelectedItem;
109 } LookInInfos;
111 typedef struct tagFD32_PRIVATE
113 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
114 } FD32_PRIVATE, *PFD32_PRIVATE;
117 /***********************************************************************
118 * Defines and global variables
121 /* Draw item constant */
122 #define ICONWIDTH 18
123 #define XTEXTOFFSET 3
125 /* AddItem flags*/
126 #define LISTEND -1
128 /* SearchItem methods */
129 #define SEARCH_PIDL 1
130 #define SEARCH_EXP 2
131 #define ITEM_NOTFOUND -1
133 /* Undefined windows message sent by CreateViewObject*/
134 #define WM_GETISHELLBROWSER WM_USER+7
136 /* NOTE
137 * Those macros exist in windowsx.h. However, you can't really use them since
138 * they rely on the UNICODE defines and can't be used inside Wine itself.
141 /* Combo box macros */
142 #define CBAddString(hwnd,str) \
143 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
144 #define CBAddStringW(hwnd,str) \
145 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
147 #define CBInsertString(hwnd,str,pos) \
148 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
150 #define CBDeleteString(hwnd,pos) \
151 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
153 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
154 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
156 #define CBGetItemDataPtr(hwnd,iItemId) \
157 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
159 #define CBGetLBText(hwnd,iItemId,str) \
160 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
162 #define CBGetCurSel(hwnd) \
163 SendMessageA(hwnd,CB_GETCURSEL,0,0);
165 #define CBSetCurSel(hwnd,pos) \
166 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
168 #define CBGetCount(hwnd) \
169 SendMessageA(hwnd,CB_GETCOUNT,0,0);
170 #define CBShowDropDown(hwnd,show) \
171 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
172 #define CBSetItemHeight(hwnd,index,height) \
173 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
175 #define CBSetExtendedUI(hwnd,flag) \
176 SendMessageA(hwnd,CB_SETEXTENDEDUI,(WPARAM)(flag),0)
178 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
179 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
181 /***********************************************************************
182 * Prototypes
185 /* Internal functions used by the dialog */
186 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
187 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
188 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
189 static BOOL FILEDLG95_OnOpen(HWND hwnd);
190 static LRESULT FILEDLG95_InitControls(HWND hwnd);
191 static void FILEDLG95_Clean(HWND hwnd);
193 /* Functions used by the shell navigation */
194 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
195 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
196 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
197 static void FILEDLG95_SHELL_Clean(HWND hwnd);
198 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
200 /* Functions used by the EDIT box */
201 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator);
203 /* Functions used by the filetype combo box */
204 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
205 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
206 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
207 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
209 /* Functions used by the Look In combo box */
210 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
211 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
212 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
213 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
214 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
215 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
216 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
217 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
218 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
220 /* Miscellaneous tool functions */
221 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
222 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
223 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
224 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
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 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode);
232 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
233 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
234 static BOOL BrowseSelectedFolder(HWND hwnd);
236 /***********************************************************************
237 * GetFileName95
239 * Creates an Open common dialog box that lets the user select
240 * the drive, directory, and the name of a file or set of files to open.
242 * IN : The FileOpenDlgInfos structure associated with the dialog
243 * OUT : TRUE on success
244 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
246 static BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
249 LRESULT lRes;
250 LPCVOID template;
251 HRSRC hRes;
252 HANDLE hDlgTmpl = 0;
253 HRESULT hr;
255 /* test for missing functionality */
256 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
258 FIXME("Flags 0x%08x not yet implemented\n",
259 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
262 /* Create the dialog from a template */
264 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
266 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
267 return FALSE;
269 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
270 !(template = LockResource( hDlgTmpl )))
272 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
273 return FALSE;
276 /* old style hook messages */
277 if (IsHooked(fodInfos))
279 fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
280 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
281 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
282 fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
285 /* Some shell namespace extensions depend on COM being initialized. */
286 hr = OleInitialize(NULL);
288 if (fodInfos->unicode)
289 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
290 template,
291 fodInfos->ofnInfos->hwndOwner,
292 FileOpenDlgProc95,
293 (LPARAM) fodInfos);
294 else
295 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
296 (LPCDLGTEMPLATEA) template,
297 fodInfos->ofnInfos->hwndOwner,
298 FileOpenDlgProc95,
299 (LPARAM) fodInfos);
300 if (SUCCEEDED(hr))
301 OleUninitialize();
303 /* Unable to create the dialog */
304 if( lRes == -1)
305 return FALSE;
307 return lRes;
310 /***********************************************************************
311 * GetFileDialog95A
313 * Call GetFileName95 with this structure and clean the memory.
315 * IN : The OPENFILENAMEA initialisation structure passed to
316 * GetOpenFileNameA win api function (see filedlg.c)
318 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
320 BOOL ret;
321 FileOpenDlgInfos fodInfos;
322 LPSTR lpstrSavDir = NULL;
323 LPWSTR title = NULL;
324 LPWSTR defext = NULL;
325 LPWSTR filter = NULL;
326 LPWSTR customfilter = NULL;
328 /* Initialize FileOpenDlgInfos structure */
329 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
331 /* Pass in the original ofn */
332 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
334 /* save current directory */
335 if (ofn->Flags & OFN_NOCHANGEDIR)
337 lpstrSavDir = MemAlloc(MAX_PATH);
338 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
341 fodInfos.unicode = FALSE;
343 /* convert all the input strings to unicode */
344 if(ofn->lpstrInitialDir)
346 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
347 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
348 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
350 else
351 fodInfos.initdir = NULL;
353 if(ofn->lpstrFile)
355 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
356 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
358 else
359 fodInfos.filename = NULL;
361 if(ofn->lpstrDefExt)
363 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
364 defext = MemAlloc((len+1)*sizeof(WCHAR));
365 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
367 fodInfos.defext = defext;
369 if(ofn->lpstrTitle)
371 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
372 title = MemAlloc((len+1)*sizeof(WCHAR));
373 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
375 fodInfos.title = title;
377 if (ofn->lpstrFilter)
379 LPCSTR s;
380 int n, len;
382 /* filter is a list... title\0ext\0......\0\0 */
383 s = ofn->lpstrFilter;
384 while (*s) s = s+strlen(s)+1;
385 s++;
386 n = s - ofn->lpstrFilter;
387 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
388 filter = MemAlloc(len*sizeof(WCHAR));
389 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
391 fodInfos.filter = filter;
393 /* convert lpstrCustomFilter */
394 if (ofn->lpstrCustomFilter)
396 LPCSTR s;
397 int n, len;
399 /* customfilter contains a pair of strings... title\0ext\0 */
400 s = ofn->lpstrCustomFilter;
401 if (*s) s = s+strlen(s)+1;
402 if (*s) s = s+strlen(s)+1;
403 n = s - ofn->lpstrCustomFilter;
404 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
405 customfilter = MemAlloc(len*sizeof(WCHAR));
406 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
408 fodInfos.customfilter = customfilter;
410 /* Initialize the dialog property */
411 fodInfos.DlgInfos.dwDlgProp = 0;
412 fodInfos.DlgInfos.hwndCustomDlg = NULL;
414 switch(iDlgType)
416 case OPEN_DIALOG :
417 ret = GetFileName95(&fodInfos);
418 break;
419 case SAVE_DIALOG :
420 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
421 ret = GetFileName95(&fodInfos);
422 break;
423 default :
424 ret = 0;
427 if (lpstrSavDir)
429 SetCurrentDirectoryA(lpstrSavDir);
430 MemFree(lpstrSavDir);
433 MemFree(title);
434 MemFree(defext);
435 MemFree(filter);
436 MemFree(customfilter);
437 MemFree(fodInfos.initdir);
438 MemFree(fodInfos.filename);
440 TRACE("selected file: %s\n",ofn->lpstrFile);
442 return ret;
445 /***********************************************************************
446 * GetFileDialog95W
448 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
449 * Call GetFileName95 with this structure and clean the memory.
452 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
454 BOOL ret;
455 FileOpenDlgInfos fodInfos;
456 LPWSTR lpstrSavDir = NULL;
458 /* Initialize FileOpenDlgInfos structure */
459 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
461 /* Pass in the original ofn */
462 fodInfos.ofnInfos = ofn;
464 fodInfos.title = ofn->lpstrTitle;
465 fodInfos.defext = ofn->lpstrDefExt;
466 fodInfos.filter = ofn->lpstrFilter;
467 fodInfos.customfilter = ofn->lpstrCustomFilter;
469 /* convert string arguments, save others */
470 if(ofn->lpstrFile)
472 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
473 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
475 else
476 fodInfos.filename = NULL;
478 if(ofn->lpstrInitialDir)
480 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
481 DWORD len = strlenW(ofn->lpstrInitialDir)+1;
482 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
483 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
485 else
486 fodInfos.initdir = NULL;
488 /* save current directory */
489 if (ofn->Flags & OFN_NOCHANGEDIR)
491 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
492 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
495 fodInfos.unicode = TRUE;
497 switch(iDlgType)
499 case OPEN_DIALOG :
500 ret = GetFileName95(&fodInfos);
501 break;
502 case SAVE_DIALOG :
503 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
504 ret = GetFileName95(&fodInfos);
505 break;
506 default :
507 ret = 0;
510 if (lpstrSavDir)
512 SetCurrentDirectoryW(lpstrSavDir);
513 MemFree(lpstrSavDir);
516 /* restore saved IN arguments and convert OUT arguments back */
517 MemFree(fodInfos.filename);
518 MemFree(fodInfos.initdir);
519 return ret;
522 /******************************************************************************
523 * COMDLG32_GetDisplayNameOf [internal]
525 * Helper function to get the display name for a pidl.
527 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
528 LPSHELLFOLDER psfDesktop;
529 STRRET strret;
531 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
532 return FALSE;
534 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
535 IShellFolder_Release(psfDesktop);
536 return FALSE;
539 IShellFolder_Release(psfDesktop);
540 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
543 /***********************************************************************
544 * ArrangeCtrlPositions [internal]
546 * NOTE: Do not change anything here without a lot of testing.
548 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
550 HWND hwndChild, hwndStc32;
551 RECT rectParent, rectChild, rectStc32;
552 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
554 /* Take into account if open as read only checkbox and help button
555 * are hidden
557 if (hide_help)
559 RECT rectHelp, rectCancel;
560 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
561 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
562 /* subtract the height of the help button plus the space between
563 * the help button and the cancel button to the height of the dialog
565 help_fixup = rectHelp.bottom - rectCancel.bottom;
569 There are two possibilities to add components to the default file dialog box.
571 By default, all the new components are added below the standard dialog box (the else case).
573 However, if there is a static text component with the stc32 id, a special case happens.
574 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
575 in the window and the cx and cy indicate how to size the window.
576 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
577 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
581 GetClientRect(hwndParentDlg, &rectParent);
583 /* when arranging controls we have to use fixed parent size */
584 rectParent.bottom -= help_fixup;
586 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
587 if (hwndStc32)
589 GetWindowRect(hwndStc32, &rectStc32);
590 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
592 /* set the size of the stc32 control according to the size of
593 * client area of the parent dialog
595 SetWindowPos(hwndStc32, 0,
596 0, 0,
597 rectParent.right, rectParent.bottom,
598 SWP_NOMOVE | SWP_NOZORDER);
600 else
601 SetRectEmpty(&rectStc32);
603 /* this part moves controls of the child dialog */
604 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
605 while (hwndChild)
607 if (hwndChild != hwndStc32)
609 GetWindowRect(hwndChild, &rectChild);
610 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
612 /* move only if stc32 exist */
613 if (hwndStc32 && rectChild.left > rectStc32.right)
615 LONG old_left = rectChild.left;
617 /* move to the right of visible controls of the parent dialog */
618 rectChild.left += rectParent.right;
619 rectChild.left -= rectStc32.right;
621 child_width_fixup = rectChild.left - old_left;
623 /* move even if stc32 doesn't exist */
624 if (rectChild.top >= rectStc32.bottom)
626 LONG old_top = rectChild.top;
628 /* move below visible controls of the parent dialog */
629 rectChild.top += rectParent.bottom;
630 rectChild.top -= rectStc32.bottom - rectStc32.top;
632 child_height_fixup = rectChild.top - old_top;
635 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
636 0, 0, SWP_NOSIZE | SWP_NOZORDER);
638 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
641 /* this part moves controls of the parent dialog */
642 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
643 while (hwndChild)
645 if (hwndChild != hwndChildDlg)
647 GetWindowRect(hwndChild, &rectChild);
648 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
650 /* left,top of stc32 marks the position of controls
651 * from the parent dialog
653 rectChild.left += rectStc32.left;
654 rectChild.top += rectStc32.top;
656 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
657 0, 0, SWP_NOSIZE | SWP_NOZORDER);
659 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
662 /* calculate the size of the resulting dialog */
664 /* here we have to use original parent size */
665 GetClientRect(hwndParentDlg, &rectParent);
666 GetClientRect(hwndChildDlg, &rectChild);
668 if (hwndStc32)
670 rectChild.right += child_width_fixup;
671 rectChild.bottom += child_height_fixup;
673 if (rectParent.right > rectChild.right)
675 rectParent.right += rectChild.right;
676 rectParent.right -= rectStc32.right - rectStc32.left;
678 else
680 rectParent.right = rectChild.right;
683 if (rectParent.bottom > rectChild.bottom)
685 rectParent.bottom += rectChild.bottom;
686 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
688 else
690 /* child dialog is higher, unconditionally set new dialog
691 * height to its size (help_fixup will be subtracted below)
693 rectParent.bottom = rectChild.bottom + help_fixup;
696 else
698 rectParent.bottom += rectChild.bottom;
701 /* finally use fixed parent size */
702 rectParent.bottom -= help_fixup;
704 /* set the size of the parent dialog */
705 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
706 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
707 SetWindowPos(hwndParentDlg, 0,
708 0, 0,
709 rectParent.right - rectParent.left,
710 rectParent.bottom - rectParent.top,
711 SWP_NOMOVE | SWP_NOZORDER);
714 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
716 switch(uMsg) {
717 case WM_INITDIALOG:
718 return TRUE;
720 return FALSE;
723 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
725 LPCVOID template;
726 HRSRC hRes;
727 HANDLE hDlgTmpl = 0;
728 HWND hChildDlg = 0;
730 TRACE("\n");
733 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
734 * structure's hInstance parameter is not a HINSTANCE, but
735 * instead a pointer to a template resource to use.
737 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
739 HINSTANCE hinst;
740 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
742 hinst = COMDLG32_hInstance;
743 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
745 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
746 return NULL;
749 else
751 hinst = fodInfos->ofnInfos->hInstance;
752 if(fodInfos->unicode)
754 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
755 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
757 else
759 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
760 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
762 if (!hRes)
764 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
765 return NULL;
767 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
768 !(template = LockResource( hDlgTmpl )))
770 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
771 return NULL;
774 if (fodInfos->unicode)
775 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
776 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
777 (LPARAM)fodInfos->ofnInfos);
778 else
779 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
780 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
781 (LPARAM)fodInfos->ofnInfos);
782 if(hChildDlg)
784 ShowWindow(hChildDlg,SW_SHOW);
785 return hChildDlg;
788 else if( IsHooked(fodInfos))
790 RECT rectHwnd;
791 struct {
792 DLGTEMPLATE tmplate;
793 WORD menu,class,title;
794 } temp;
795 GetClientRect(hwnd,&rectHwnd);
796 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
797 temp.tmplate.dwExtendedStyle = 0;
798 temp.tmplate.cdit = 0;
799 temp.tmplate.x = 0;
800 temp.tmplate.y = 0;
801 temp.tmplate.cx = 0;
802 temp.tmplate.cy = 0;
803 temp.menu = temp.class = temp.title = 0;
805 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
806 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
808 return hChildDlg;
810 return NULL;
813 /***********************************************************************
814 * SendCustomDlgNotificationMessage
816 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
819 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
821 LRESULT hook_result = 0;
823 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
825 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
827 if(!fodInfos) return 0;
829 if(fodInfos->DlgInfos.hwndCustomDlg)
831 TRACE("CALL NOTIFY for %x\n", uCode);
832 if(fodInfos->unicode)
834 OFNOTIFYW ofnNotify;
835 ofnNotify.hdr.hwndFrom=hwndParentDlg;
836 ofnNotify.hdr.idFrom=0;
837 ofnNotify.hdr.code = uCode;
838 ofnNotify.lpOFN = fodInfos->ofnInfos;
839 ofnNotify.pszFile = NULL;
840 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
842 else
844 OFNOTIFYA ofnNotify;
845 ofnNotify.hdr.hwndFrom=hwndParentDlg;
846 ofnNotify.hdr.idFrom=0;
847 ofnNotify.hdr.code = uCode;
848 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
849 ofnNotify.pszFile = NULL;
850 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
852 TRACE("RET NOTIFY\n");
854 TRACE("Retval: 0x%08lx\n", hook_result);
855 return hook_result;
858 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer)
860 UINT sizeUsed = 0, n, total;
861 LPWSTR lpstrFileList = NULL;
862 WCHAR lpstrCurrentDir[MAX_PATH];
863 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
865 TRACE("CDM_GETFILEPATH:\n");
867 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
868 return -1;
870 /* get path and filenames */
871 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrCurrentDir);
872 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
874 TRACE("path >%s< filespec >%s< %d files\n",
875 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
877 if( fodInfos->unicode )
879 LPWSTR bufW = buffer;
880 total = strlenW(lpstrCurrentDir) + 1 + sizeUsed;
882 /* Prepend the current path */
883 n = strlenW(lpstrCurrentDir) + 1;
884 memcpy( bufW, lpstrCurrentDir, min(n,size) * sizeof(WCHAR));
885 if(n<size)
887 /* 'n' includes trailing \0 */
888 bufW[n-1] = '\\';
889 memcpy( &bufW[n], lpstrFileList, (size-n)*sizeof(WCHAR) );
891 TRACE("returned -> %s\n",debugstr_wn(bufW, total));
893 else
895 LPSTR bufA = buffer;
896 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
897 NULL, 0, NULL, NULL);
898 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
899 NULL, 0, NULL, NULL);
901 /* Prepend the current path */
902 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
903 bufA, size, NULL, NULL);
905 if(n<size)
907 /* 'n' includes trailing \0 */
908 bufA[n-1] = '\\';
909 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
910 &bufA[n], size-n, NULL, NULL);
913 TRACE("returned -> %s\n",debugstr_an(bufA, total));
915 MemFree(lpstrFileList);
917 return total;
920 static INT_PTR FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer)
922 UINT sizeUsed = 0;
923 LPWSTR lpstrFileList = NULL;
924 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
926 TRACE("CDM_GETSPEC:\n");
928 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
929 if( fodInfos->unicode )
931 LPWSTR bufW = buffer;
932 memcpy( bufW, lpstrFileList, sizeof(WCHAR)*sizeUsed );
934 else
936 LPSTR bufA = buffer;
937 sizeUsed = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed,
938 NULL, 0, NULL, NULL);
939 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
940 bufA, size, NULL, NULL);
942 MemFree(lpstrFileList);
944 return sizeUsed;
947 /***********************************************************************
948 * FILEDLG95_HandleCustomDialogMessages
950 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
952 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
954 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
955 WCHAR lpstrPath[MAX_PATH];
956 INT_PTR retval;
958 if(!fodInfos) return FALSE;
960 switch(uMsg)
962 case CDM_GETFILEPATH:
963 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
964 break;
966 case CDM_GETFOLDERPATH:
967 TRACE("CDM_GETFOLDERPATH:\n");
968 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
969 if (lParam)
971 if (fodInfos->unicode)
972 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
973 else
974 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
975 (LPSTR)lParam, (int)wParam, NULL, NULL);
977 retval = strlenW(lpstrPath);
978 break;
980 case CDM_GETSPEC:
981 retval = FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
982 break;
984 case CDM_SETCONTROLTEXT:
985 TRACE("CDM_SETCONTROLTEXT:\n");
986 if ( lParam )
988 if( fodInfos->unicode )
989 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
990 else
991 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
993 retval = TRUE;
994 break;
996 case CDM_HIDECONTROL:
997 /* MSDN states that it should fail for not OFN_EXPLORER case */
998 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1000 HWND control = GetDlgItem( hwnd, wParam );
1001 if (control) ShowWindow( control, SW_HIDE );
1002 retval = TRUE;
1004 else retval = FALSE;
1005 break;
1007 default:
1008 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1009 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1010 return FALSE;
1012 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1013 return TRUE;
1016 /***********************************************************************
1017 * FileOpenDlgProc95
1019 * File open dialog procedure
1021 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1023 #if 0
1024 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
1025 #endif
1027 switch(uMsg)
1029 case WM_INITDIALOG:
1031 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1033 /* Adds the FileOpenDlgInfos in the property list of the dialog
1034 so it will be easily accessible through a GetPropA(...) */
1035 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
1037 fodInfos->DlgInfos.hwndCustomDlg =
1038 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1040 FILEDLG95_InitControls(hwnd);
1042 if (fodInfos->DlgInfos.hwndCustomDlg)
1044 RECT rc;
1045 UINT flags = SWP_NOACTIVATE;
1047 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1048 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1050 /* resize the custom dialog to the parent size */
1051 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1052 GetClientRect(hwnd, &rc);
1053 else
1055 /* our own fake template is zero sized and doesn't have
1056 * children, so there is no need to resize it.
1057 * Picasa depends on it.
1059 flags |= SWP_NOSIZE;
1060 SetRectEmpty(&rc);
1062 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1063 0, 0, rc.right, rc.bottom, flags);
1066 FILEDLG95_FillControls(hwnd, wParam, lParam);
1068 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1069 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1070 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1071 return 0;
1073 case WM_COMMAND:
1074 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1075 case WM_DRAWITEM:
1077 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1079 case IDC_LOOKIN:
1080 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1081 return TRUE;
1084 return FALSE;
1086 case WM_GETISHELLBROWSER:
1087 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1089 case WM_DESTROY:
1090 RemovePropA(hwnd, FileOpenDlgInfosStr);
1091 return FALSE;
1093 case WM_NOTIFY:
1095 LPNMHDR lpnmh = (LPNMHDR)lParam;
1096 UINT stringId = -1;
1098 /* set up the button tooltips strings */
1099 if(TTN_GETDISPINFOA == lpnmh->code )
1101 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1102 switch(lpnmh->idFrom )
1104 /* Up folder button */
1105 case FCIDM_TB_UPFOLDER:
1106 stringId = IDS_UPFOLDER;
1107 break;
1108 /* New folder button */
1109 case FCIDM_TB_NEWFOLDER:
1110 stringId = IDS_NEWFOLDER;
1111 break;
1112 /* List option button */
1113 case FCIDM_TB_SMALLICON:
1114 stringId = IDS_LISTVIEW;
1115 break;
1116 /* Details option button */
1117 case FCIDM_TB_REPORTVIEW:
1118 stringId = IDS_REPORTVIEW;
1119 break;
1120 /* Desktop button */
1121 case FCIDM_TB_DESKTOP:
1122 stringId = IDS_TODESKTOP;
1123 break;
1124 default:
1125 stringId = 0;
1127 lpdi->hinst = COMDLG32_hInstance;
1128 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1130 return FALSE;
1132 default :
1133 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1134 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1135 return FALSE;
1139 /***********************************************************************
1140 * FILEDLG95_InitControls
1142 * WM_INITDIALOG message handler (before hook notification)
1144 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1146 int win2000plus = 0;
1147 int win98plus = 0;
1148 int handledPath = FALSE;
1149 OSVERSIONINFOA osVi;
1150 static const WCHAR szwSlash[] = { '\\', 0 };
1151 static const WCHAR szwStar[] = { '*',0 };
1153 TBBUTTON tbb[] =
1155 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1156 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1157 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1158 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1159 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1160 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1161 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1162 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1163 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1165 TBADDBITMAP tba[2];
1166 RECT rectTB;
1167 RECT rectlook;
1168 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1170 tba[0].hInst = HINST_COMMCTRL;
1171 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1172 tba[1].hInst = COMDLG32_hInstance;
1173 tba[1].nID = 800;
1175 TRACE("%p\n", fodInfos);
1177 /* Get windows version emulating */
1178 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1179 GetVersionExA(&osVi);
1180 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1181 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1182 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1183 win2000plus = (osVi.dwMajorVersion > 4);
1184 if (win2000plus) win98plus = TRUE;
1186 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1188 /* Get the hwnd of the controls */
1189 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1190 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1191 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1193 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1194 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1196 /* construct the toolbar */
1197 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1198 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1200 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1201 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1202 rectTB.left = rectlook.right;
1203 rectTB.top = rectlook.top-1;
1205 if (fodInfos->unicode)
1206 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1207 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1208 rectTB.left, rectTB.top,
1209 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1210 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1211 else
1212 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1213 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1214 rectTB.left, rectTB.top,
1215 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1216 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1218 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1220 /* FIXME: use TB_LOADIMAGES when implemented */
1221 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1222 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1223 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1225 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1226 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1228 /* Set the window text with the text specified in the OPENFILENAME structure */
1229 if(fodInfos->title)
1231 SetWindowTextW(hwnd,fodInfos->title);
1233 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1235 WCHAR buf[16];
1236 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1237 SetWindowTextW(hwnd, buf);
1240 /* Initialise the file name edit control */
1241 handledPath = FALSE;
1242 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1244 if(fodInfos->filename)
1246 /* 1. If win2000 or higher and filename contains a path, use it
1247 in preference over the lpstrInitialDir */
1248 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1249 WCHAR tmpBuf[MAX_PATH];
1250 WCHAR *nameBit;
1251 DWORD result;
1253 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1254 if (result) {
1256 /* nameBit is always shorter than the original filename */
1257 strcpyW(fodInfos->filename,nameBit);
1259 *nameBit = 0x00;
1260 if (fodInfos->initdir == NULL)
1261 MemFree(fodInfos->initdir);
1262 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1263 strcpyW(fodInfos->initdir, tmpBuf);
1264 handledPath = TRUE;
1265 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1266 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1268 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1270 } else {
1271 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1275 /* 2. (All platforms) If initdir is not null, then use it */
1276 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1277 (*fodInfos->initdir!=0x00))
1279 /* Work out the proper path as supplied one might be relative */
1280 /* (Here because supplying '.' as dir browses to My Computer) */
1281 if (handledPath==FALSE) {
1282 WCHAR tmpBuf[MAX_PATH];
1283 WCHAR tmpBuf2[MAX_PATH];
1284 WCHAR *nameBit;
1285 DWORD result;
1287 strcpyW(tmpBuf, fodInfos->initdir);
1288 if( PathFileExistsW(tmpBuf) ) {
1289 /* initdir does not have to be a directory. If a file is
1290 * specified, the dir part is taken */
1291 if( PathIsDirectoryW(tmpBuf)) {
1292 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1293 strcatW(tmpBuf, szwSlash);
1295 strcatW(tmpBuf, szwStar);
1297 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1298 if (result) {
1299 *nameBit = 0x00;
1300 MemFree(fodInfos->initdir);
1301 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1302 strcpyW(fodInfos->initdir, tmpBuf2);
1303 handledPath = TRUE;
1304 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1307 else if (fodInfos->initdir)
1309 MemFree(fodInfos->initdir);
1310 fodInfos->initdir = NULL;
1311 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1316 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1317 (*fodInfos->initdir==0x00)))
1319 /* 3. All except w2k+: if filename contains a path use it */
1320 if (!win2000plus && fodInfos->filename &&
1321 *fodInfos->filename &&
1322 strpbrkW(fodInfos->filename, szwSlash)) {
1323 WCHAR tmpBuf[MAX_PATH];
1324 WCHAR *nameBit;
1325 DWORD result;
1327 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1328 tmpBuf, &nameBit);
1329 if (result) {
1330 int len;
1332 /* nameBit is always shorter than the original filename */
1333 strcpyW(fodInfos->filename, nameBit);
1334 *nameBit = 0x00;
1336 len = strlenW(tmpBuf);
1337 MemFree(fodInfos->initdir);
1338 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1339 strcpyW(fodInfos->initdir, tmpBuf);
1341 handledPath = TRUE;
1342 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1343 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1345 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1348 /* 4. win98+ and win2000+ if any files of specified filter types in
1349 current directory, use it */
1350 if ( win98plus && handledPath == FALSE &&
1351 fodInfos->filter && *fodInfos->filter) {
1353 BOOL searchMore = TRUE;
1354 LPCWSTR lpstrPos = fodInfos->filter;
1355 WIN32_FIND_DATAW FindFileData;
1356 HANDLE hFind;
1358 while (searchMore)
1360 /* filter is a list... title\0ext\0......\0\0 */
1362 /* Skip the title */
1363 if(! *lpstrPos) break; /* end */
1364 lpstrPos += strlenW(lpstrPos) + 1;
1366 /* See if any files exist in the current dir with this extension */
1367 if(! *lpstrPos) break; /* end */
1369 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1371 if (hFind == INVALID_HANDLE_VALUE) {
1372 /* None found - continue search */
1373 lpstrPos += strlenW(lpstrPos) + 1;
1375 } else {
1376 searchMore = FALSE;
1378 MemFree(fodInfos->initdir);
1379 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1380 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1382 handledPath = TRUE;
1383 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1384 debugstr_w(lpstrPos));
1385 break;
1390 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1392 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1393 if (handledPath == FALSE && (win2000plus || win98plus)) {
1394 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1396 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1398 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1400 /* last fallback */
1401 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1402 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1403 } else {
1404 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1406 } else {
1407 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1409 handledPath = TRUE;
1410 } else if (handledPath==FALSE) {
1411 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1412 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1413 handledPath = TRUE;
1414 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1417 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1418 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1420 /* Must the open as read only check box be checked ?*/
1421 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1423 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1426 /* Must the open as read only check box be hidden? */
1427 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1429 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1430 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1433 /* Must the help button be hidden? */
1434 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1436 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1437 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1440 /* Resize the height, if open as read only checkbox ad help button
1441 are hidden and we are not using a custom template nor a customDialog
1443 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1444 (!(fodInfos->ofnInfos->Flags &
1445 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1446 (!fodInfos->DlgInfos.hwndCustomDlg ))
1448 RECT rectDlg, rectHelp, rectCancel;
1449 GetWindowRect(hwnd, &rectDlg);
1450 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1451 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1452 /* subtract the height of the help button plus the space between
1453 the help button and the cancel button to the height of the dialog */
1454 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1455 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1456 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1458 /* change Open to Save */
1459 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1461 WCHAR buf[16];
1462 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1463 SetDlgItemTextW(hwnd, IDOK, buf);
1464 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1465 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1467 return 0;
1470 /***********************************************************************
1471 * FILEDLG95_FillControls
1473 * WM_INITDIALOG message handler (after hook notification)
1475 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1477 LPITEMIDLIST pidlItemId = NULL;
1479 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1481 TRACE("dir=%s file=%s\n",
1482 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1484 /* Get the initial directory pidl */
1486 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1488 WCHAR path[MAX_PATH];
1490 GetCurrentDirectoryW(MAX_PATH,path);
1491 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1494 /* Initialise shell objects */
1495 FILEDLG95_SHELL_Init(hwnd);
1497 /* Initialize the Look In combo box */
1498 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1500 /* Initialize the filter combo box */
1501 FILEDLG95_FILETYPE_Init(hwnd);
1503 /* Browse to the initial directory */
1504 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1506 /* Free pidlItem memory */
1507 COMDLG32_SHFree(pidlItemId);
1509 return TRUE;
1511 /***********************************************************************
1512 * FILEDLG95_Clean
1514 * Regroups all the cleaning functions of the filedlg
1516 void FILEDLG95_Clean(HWND hwnd)
1518 FILEDLG95_FILETYPE_Clean(hwnd);
1519 FILEDLG95_LOOKIN_Clean(hwnd);
1520 FILEDLG95_SHELL_Clean(hwnd);
1522 /***********************************************************************
1523 * FILEDLG95_OnWMCommand
1525 * WM_COMMAND message handler
1527 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1529 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1530 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1531 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1533 switch(wID)
1535 /* OK button */
1536 case IDOK:
1537 FILEDLG95_OnOpen(hwnd);
1538 break;
1539 /* Cancel button */
1540 case IDCANCEL:
1541 FILEDLG95_Clean(hwnd);
1542 EndDialog(hwnd, FALSE);
1543 break;
1544 /* Filetype combo box */
1545 case IDC_FILETYPE:
1546 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1547 break;
1548 /* LookIn combo box */
1549 case IDC_LOOKIN:
1550 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1551 break;
1553 /* --- toolbar --- */
1554 /* Up folder button */
1555 case FCIDM_TB_UPFOLDER:
1556 FILEDLG95_SHELL_UpFolder(hwnd);
1557 break;
1558 /* New folder button */
1559 case FCIDM_TB_NEWFOLDER:
1560 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1561 break;
1562 /* List option button */
1563 case FCIDM_TB_SMALLICON:
1564 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1565 break;
1566 /* Details option button */
1567 case FCIDM_TB_REPORTVIEW:
1568 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1569 break;
1570 /* Details option button */
1571 case FCIDM_TB_DESKTOP:
1572 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1573 break;
1575 case IDC_FILENAME:
1576 break;
1579 /* Do not use the listview selection anymore */
1580 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1581 return 0;
1584 /***********************************************************************
1585 * FILEDLG95_OnWMGetIShellBrowser
1587 * WM_GETISHELLBROWSER message handler
1589 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1592 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1594 TRACE("\n");
1596 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1598 return TRUE;
1602 /***********************************************************************
1603 * FILEDLG95_SendFileOK
1605 * Sends the CDN_FILEOK notification if required
1607 * RETURNS
1608 * TRUE if the dialog should close
1609 * FALSE if the dialog should not be closed
1611 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1613 /* ask the hook if we can close */
1614 if(IsHooked(fodInfos))
1616 LRESULT retval;
1618 TRACE("---\n");
1619 /* First send CDN_FILEOK as MSDN doc says */
1620 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1621 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1623 TRACE("canceled\n");
1624 return (retval == 0);
1627 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1628 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1629 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1630 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1632 TRACE("canceled\n");
1633 return (retval == 0);
1636 return TRUE;
1639 /***********************************************************************
1640 * FILEDLG95_OnOpenMultipleFiles
1642 * Handles the opening of multiple files.
1644 * FIXME
1645 * check destination buffer size
1647 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1649 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1650 UINT nCount, nSizePath;
1651 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1653 TRACE("\n");
1655 if(fodInfos->unicode)
1657 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1658 ofn->lpstrFile[0] = '\0';
1660 else
1662 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1663 ofn->lpstrFile[0] = '\0';
1666 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1668 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1669 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1670 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1672 LPWSTR lpstrTemp = lpstrFileList;
1674 for ( nCount = 0; nCount < nFileCount; nCount++ )
1676 LPITEMIDLIST pidl;
1678 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1679 if (!pidl)
1681 WCHAR lpstrNotFound[100];
1682 WCHAR lpstrMsg[100];
1683 WCHAR tmp[400];
1684 static const WCHAR nl[] = {'\n',0};
1686 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1687 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1689 strcpyW(tmp, lpstrTemp);
1690 strcatW(tmp, nl);
1691 strcatW(tmp, lpstrNotFound);
1692 strcatW(tmp, nl);
1693 strcatW(tmp, lpstrMsg);
1695 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1696 return FALSE;
1699 /* move to the next file in the list of files */
1700 lpstrTemp += strlenW(lpstrTemp) + 1;
1701 COMDLG32_SHFree(pidl);
1705 nSizePath = strlenW(lpstrPathSpec) + 1;
1706 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1708 /* For "oldstyle" dialog the components have to
1709 be separated by blanks (not '\0'!) and short
1710 filenames have to be used! */
1711 FIXME("Components have to be separated by blanks\n");
1713 if(fodInfos->unicode)
1715 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1716 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1717 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1719 else
1721 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1723 if (ofn->lpstrFile != NULL)
1725 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1726 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1727 if (ofn->nMaxFile > nSizePath)
1729 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1730 ofn->lpstrFile + nSizePath,
1731 ofn->nMaxFile - nSizePath, NULL, NULL);
1736 fodInfos->ofnInfos->nFileOffset = nSizePath;
1737 fodInfos->ofnInfos->nFileExtension = 0;
1739 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1740 return FALSE;
1742 /* clean and exit */
1743 FILEDLG95_Clean(hwnd);
1744 return EndDialog(hwnd,TRUE);
1747 /***********************************************************************
1748 * FILEDLG95_OnOpen
1750 * Ok button WM_COMMAND message handler
1752 * If the function succeeds, the return value is nonzero.
1754 #define ONOPEN_BROWSE 1
1755 #define ONOPEN_OPEN 2
1756 #define ONOPEN_SEARCH 3
1757 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1759 WCHAR strMsgTitle[MAX_PATH];
1760 WCHAR strMsgText [MAX_PATH];
1761 if (idCaption)
1762 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1763 else
1764 strMsgTitle[0] = '\0';
1765 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1766 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1769 BOOL FILEDLG95_OnOpen(HWND hwnd)
1771 LPWSTR lpstrFileList;
1772 UINT nFileCount = 0;
1773 UINT sizeUsed = 0;
1774 BOOL ret = TRUE;
1775 WCHAR lpstrPathAndFile[MAX_PATH];
1776 WCHAR lpstrTemp[MAX_PATH];
1777 LPSHELLFOLDER lpsf = NULL;
1778 int nOpenAction;
1779 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1781 TRACE("hwnd=%p\n", hwnd);
1783 /* get the files from the edit control */
1784 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1786 /* try if the user selected a folder in the shellview */
1787 if(nFileCount == 0)
1789 BrowseSelectedFolder(hwnd);
1790 return FALSE;
1793 if(nFileCount > 1)
1795 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1796 goto ret;
1799 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1802 Step 1: Build a complete path name from the current folder and
1803 the filename or path in the edit box.
1804 Special cases:
1805 - the path in the edit box is a root path
1806 (with or without drive letter)
1807 - the edit box contains ".." (or a path with ".." in it)
1810 /* Get the current directory name */
1811 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1813 /* last fallback */
1814 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1816 PathAddBackslashW(lpstrPathAndFile);
1818 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1820 /* if the user specifyed a fully qualified path use it */
1821 if(PathIsRelativeW(lpstrFileList))
1823 strcatW(lpstrPathAndFile, lpstrFileList);
1825 else
1827 /* does the path have a drive letter? */
1828 if (PathGetDriveNumberW(lpstrFileList) == -1)
1829 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1830 else
1831 strcpyW(lpstrPathAndFile, lpstrFileList);
1834 /* resolve "." and ".." */
1835 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1836 strcpyW(lpstrPathAndFile, lpstrTemp);
1837 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1839 MemFree(lpstrFileList);
1842 Step 2: here we have a cleaned up path
1844 We have to parse the path step by step to see if we have to browse
1845 to a folder if the path points to a directory or the last
1846 valid element is a directory.
1848 valid variables:
1849 lpstrPathAndFile: cleaned up path
1852 if (nFileCount &&
1853 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1854 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1855 nOpenAction = ONOPEN_OPEN;
1856 else
1857 nOpenAction = ONOPEN_BROWSE;
1859 /* don't apply any checks with OFN_NOVALIDATE */
1861 LPWSTR lpszTemp, lpszTemp1;
1862 LPITEMIDLIST pidl = NULL;
1863 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1865 /* check for invalid chars */
1866 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1868 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1869 ret = FALSE;
1870 goto ret;
1873 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1875 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1876 while (lpszTemp1)
1878 LPSHELLFOLDER lpsfChild;
1879 WCHAR lpwstrTemp[MAX_PATH];
1880 DWORD dwEaten, dwAttributes;
1881 LPWSTR p;
1883 strcpyW(lpwstrTemp, lpszTemp);
1884 p = PathFindNextComponentW(lpwstrTemp);
1886 if (!p) break; /* end of path */
1888 *p = 0;
1889 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1891 /* There are no wildcards when OFN_NOVALIDATE is set */
1892 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1894 static const WCHAR wszWild[] = { '*', '?', 0 };
1895 /* if the last element is a wildcard do a search */
1896 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1898 nOpenAction = ONOPEN_SEARCH;
1899 break;
1902 lpszTemp1 = lpszTemp;
1904 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1906 /* append a backslash to drive letters */
1907 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1908 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1909 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1911 PathAddBackslashW(lpwstrTemp);
1914 dwAttributes = SFGAO_FOLDER;
1915 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1917 /* the path component is valid, we have a pidl of the next path component */
1918 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
1919 if(dwAttributes & SFGAO_FOLDER)
1921 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1923 ERR("bind to failed\n"); /* should not fail */
1924 break;
1926 IShellFolder_Release(lpsf);
1927 lpsf = lpsfChild;
1928 lpsfChild = NULL;
1930 else
1932 TRACE("value\n");
1934 /* end dialog, return value */
1935 nOpenAction = ONOPEN_OPEN;
1936 break;
1938 COMDLG32_SHFree(pidl);
1939 pidl = NULL;
1941 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1943 if(*lpszTemp) /* points to trailing null for last path element */
1945 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1947 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1948 break;
1951 else
1953 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1954 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1956 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1957 break;
1960 /* change to the current folder */
1961 nOpenAction = ONOPEN_OPEN;
1962 break;
1964 else
1966 nOpenAction = ONOPEN_OPEN;
1967 break;
1970 if(pidl) COMDLG32_SHFree(pidl);
1974 Step 3: here we have a cleaned up and validated path
1976 valid variables:
1977 lpsf: ShellFolder bound to the rightmost valid path component
1978 lpstrPathAndFile: cleaned up path
1979 nOpenAction: action to do
1981 TRACE("end validate sf=%p\n", lpsf);
1983 switch(nOpenAction)
1985 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1986 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1988 int iPos;
1989 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1990 DWORD len;
1992 /* replace the current filter */
1993 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1994 len = strlenW(lpszTemp)+1;
1995 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1996 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1998 /* set the filter cb to the extension when possible */
1999 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2000 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2002 /* fall through */
2003 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2004 TRACE("ONOPEN_BROWSE\n");
2006 IPersistFolder2 * ppf2;
2007 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2009 LPITEMIDLIST pidlCurrent;
2010 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2011 IPersistFolder2_Release(ppf2);
2012 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2014 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE)))
2016 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2019 else if( nOpenAction == ONOPEN_SEARCH )
2021 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2023 COMDLG32_SHFree(pidlCurrent);
2024 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2027 ret = FALSE;
2028 break;
2029 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2030 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2032 WCHAR *ext = NULL;
2034 /* update READONLY check box flag */
2035 if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2036 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2037 else
2038 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2040 /* Attach the file extension with file name*/
2041 ext = PathFindExtensionW(lpstrPathAndFile);
2042 if (! *ext)
2044 /* if no extension is specified with file name, then */
2045 /* attach the extension from file filter or default one */
2047 WCHAR *filterExt = NULL;
2048 LPWSTR lpstrFilter = NULL;
2049 static const WCHAR szwDot[] = {'.',0};
2050 int PathLength = strlenW(lpstrPathAndFile);
2052 /* Attach the dot*/
2053 strcatW(lpstrPathAndFile, szwDot);
2055 /*Get the file extension from file type filter*/
2056 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2057 fodInfos->ofnInfos->nFilterIndex-1);
2059 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2060 filterExt = PathFindExtensionW(lpstrFilter);
2062 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2063 strcatW(lpstrPathAndFile, filterExt + 1);
2064 else if ( fodInfos->defext ) /* attach the default file extension*/
2065 strcatW(lpstrPathAndFile, fodInfos->defext);
2067 /* In Open dialog: if file does not exist try without extension */
2068 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2069 lpstrPathAndFile[PathLength] = '\0';
2072 if (fodInfos->defext) /* add default extension */
2074 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2075 if (*ext)
2076 ext++;
2077 if (!lstrcmpiW(fodInfos->defext, ext))
2078 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2079 else
2080 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2083 /* In Save dialog: check if the file already exists */
2084 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2085 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2086 && PathFileExistsW(lpstrPathAndFile))
2088 WCHAR lpstrOverwrite[100];
2089 int answer;
2091 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2092 answer = MessageBoxW(hwnd, lpstrOverwrite, 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(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2104 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2106 LPWSTR lpszTemp;
2108 /* fill destination buffer */
2109 if (fodInfos->ofnInfos->lpstrFile)
2111 if(fodInfos->unicode)
2113 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2115 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2116 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2117 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2119 else
2121 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2123 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2124 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2125 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2126 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2130 /* set filename offset */
2131 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2132 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2134 /* set extension offset */
2135 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2136 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2138 /* set the lpstrFileTitle */
2139 if(fodInfos->ofnInfos->lpstrFileTitle)
2141 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2142 if(fodInfos->unicode)
2144 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2145 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2147 else
2149 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2150 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2151 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2155 /* copy currently selected filter to lpstrCustomFilter */
2156 if (fodInfos->ofnInfos->lpstrCustomFilter)
2158 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2159 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2160 NULL, 0, NULL, NULL);
2161 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2163 LPSTR s = ofn->lpstrCustomFilter;
2164 s += strlen(ofn->lpstrCustomFilter)+1;
2165 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2166 s, len, NULL, NULL);
2171 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2172 goto ret;
2174 TRACE("close\n");
2175 FILEDLG95_Clean(hwnd);
2176 ret = EndDialog(hwnd, TRUE);
2178 else
2180 WORD size;
2182 size = strlenW(lpstrPathAndFile) + 1;
2183 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2184 size += 1;
2185 /* return needed size in first two bytes of lpstrFile */
2186 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2187 FILEDLG95_Clean(hwnd);
2188 ret = EndDialog(hwnd, FALSE);
2189 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2191 goto ret;
2193 break;
2196 ret:
2197 if(lpsf) IShellFolder_Release(lpsf);
2198 return ret;
2201 /***********************************************************************
2202 * FILEDLG95_SHELL_Init
2204 * Initialisation of the shell objects
2206 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2208 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2210 TRACE("\n");
2213 * Initialisation of the FileOpenDialogInfos structure
2216 /* Shell */
2218 /*ShellInfos */
2219 fodInfos->ShellInfos.hwndOwner = hwnd;
2221 /* Disable multi-select if flag not set */
2222 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2224 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2226 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2227 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2229 /* Construct the IShellBrowser interface */
2230 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2232 return NOERROR;
2235 /***********************************************************************
2236 * FILEDLG95_SHELL_ExecuteCommand
2238 * Change the folder option and refresh the view
2239 * If the function succeeds, the return value is nonzero.
2241 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2243 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2245 IContextMenu * pcm;
2246 TRACE("(%p,%p)\n", hwnd, lpVerb);
2248 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2249 SVGIO_BACKGROUND,
2250 &IID_IContextMenu,
2251 (LPVOID*)&pcm)))
2253 CMINVOKECOMMANDINFO ci;
2254 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2255 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2256 ci.lpVerb = lpVerb;
2257 ci.hwnd = hwnd;
2259 IContextMenu_InvokeCommand(pcm, &ci);
2260 IContextMenu_Release(pcm);
2263 return FALSE;
2266 /***********************************************************************
2267 * FILEDLG95_SHELL_UpFolder
2269 * Browse to the specified object
2270 * If the function succeeds, the return value is nonzero.
2272 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2274 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2276 TRACE("\n");
2278 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2279 NULL,
2280 SBSP_PARENT)))
2282 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2283 return TRUE;
2285 return FALSE;
2288 /***********************************************************************
2289 * FILEDLG95_SHELL_BrowseToDesktop
2291 * Browse to the Desktop
2292 * If the function succeeds, the return value is nonzero.
2294 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2296 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2297 LPITEMIDLIST pidl;
2298 HRESULT hres;
2300 TRACE("\n");
2302 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2303 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2304 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2305 COMDLG32_SHFree(pidl);
2306 return SUCCEEDED(hres);
2308 /***********************************************************************
2309 * FILEDLG95_SHELL_Clean
2311 * Cleans the memory used by shell objects
2313 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2315 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2317 TRACE("\n");
2319 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2321 /* clean Shell interfaces */
2322 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2323 IShellView_Release(fodInfos->Shell.FOIShellView);
2324 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2325 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2326 if (fodInfos->Shell.FOIDataObject)
2327 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2330 /***********************************************************************
2331 * FILEDLG95_FILETYPE_Init
2333 * Initialisation of the file type combo box
2335 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2337 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2338 int nFilters = 0; /* number of filters */
2339 int nFilterIndexCB;
2341 TRACE("\n");
2343 if(fodInfos->customfilter)
2345 /* customfilter has one entry... title\0ext\0
2346 * Set first entry of combo box item with customfilter
2348 LPWSTR lpstrExt;
2349 LPCWSTR lpstrPos = fodInfos->customfilter;
2351 /* Get the title */
2352 lpstrPos += strlenW(fodInfos->customfilter) + 1;
2354 /* Copy the extensions */
2355 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2356 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2357 strcpyW(lpstrExt,lpstrPos);
2359 /* Add the item at the end of the combo */
2360 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2361 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2362 nFilters++;
2364 if(fodInfos->filter)
2366 LPCWSTR lpstrPos = fodInfos->filter;
2368 for(;;)
2370 /* filter is a list... title\0ext\0......\0\0
2371 * Set the combo item text to the title and the item data
2372 * to the ext
2374 LPCWSTR lpstrDisplay;
2375 LPWSTR lpstrExt;
2377 /* Get the title */
2378 if(! *lpstrPos) break; /* end */
2379 lpstrDisplay = lpstrPos;
2380 lpstrPos += strlenW(lpstrPos) + 1;
2382 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2384 nFilters++;
2386 /* Copy the extensions */
2387 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2388 strcpyW(lpstrExt,lpstrPos);
2389 lpstrPos += strlenW(lpstrPos) + 1;
2391 /* Add the item at the end of the combo */
2392 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2394 /* malformed filters are added anyway... */
2395 if (!*lpstrExt) break;
2400 * Set the current filter to the one specified
2401 * in the initialisation structure
2403 if (fodInfos->filter || fodInfos->customfilter)
2405 LPWSTR lpstrFilter;
2407 /* Check to make sure our index isn't out of bounds. */
2408 if ( fodInfos->ofnInfos->nFilterIndex >
2409 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2410 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2412 /* set default filter index */
2413 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2414 fodInfos->ofnInfos->nFilterIndex = 1;
2416 /* calculate index of Combo Box item */
2417 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2418 if (fodInfos->customfilter == NULL)
2419 nFilterIndexCB--;
2421 /* Set the current index selection. */
2422 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2424 /* Get the corresponding text string from the combo box. */
2425 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2426 nFilterIndexCB);
2428 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2429 lpstrFilter = NULL;
2431 if(lpstrFilter)
2433 DWORD len;
2434 CharLowerW(lpstrFilter); /* lowercase */
2435 len = strlenW(lpstrFilter)+1;
2436 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2437 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2439 } else
2440 fodInfos->ofnInfos->nFilterIndex = 0;
2441 return S_OK;
2444 /***********************************************************************
2445 * FILEDLG95_FILETYPE_OnCommand
2447 * WM_COMMAND of the file type combo box
2448 * If the function succeeds, the return value is nonzero.
2450 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2452 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2454 switch(wNotifyCode)
2456 case CBN_SELENDOK:
2458 LPWSTR lpstrFilter;
2460 /* Get the current item of the filetype combo box */
2461 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2463 /* set the current filter index */
2464 fodInfos->ofnInfos->nFilterIndex = iItem +
2465 (fodInfos->customfilter == NULL ? 1 : 0);
2467 /* Set the current filter with the current selection */
2468 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2470 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2471 iItem);
2472 if((INT_PTR)lpstrFilter != CB_ERR)
2474 DWORD len;
2475 CharLowerW(lpstrFilter); /* lowercase */
2476 len = strlenW(lpstrFilter)+1;
2477 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2478 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2479 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2482 /* Refresh the actual view to display the included items*/
2483 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2486 return FALSE;
2488 /***********************************************************************
2489 * FILEDLG95_FILETYPE_SearchExt
2491 * searches for an extension in the filetype box
2493 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2495 int i, iCount = CBGetCount(hwnd);
2497 TRACE("%s\n", debugstr_w(lpstrExt));
2499 if(iCount != CB_ERR)
2501 for(i=0;i<iCount;i++)
2503 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2504 return i;
2507 return -1;
2510 /***********************************************************************
2511 * FILEDLG95_FILETYPE_Clean
2513 * Clean the memory used by the filetype combo box
2515 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2517 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2518 int iPos;
2519 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2521 TRACE("\n");
2523 /* Delete each string of the combo and their associated data */
2524 if(iCount != CB_ERR)
2526 for(iPos = iCount-1;iPos>=0;iPos--)
2528 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2529 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2532 /* Current filter */
2533 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2537 /***********************************************************************
2538 * FILEDLG95_LOOKIN_Init
2540 * Initialisation of the look in combo box
2543 /* Small helper function, to determine if the unixfs shell extension is rooted
2544 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2546 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2547 HKEY hKey;
2548 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2549 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2550 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2551 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2552 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2553 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2554 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2556 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2557 return FALSE;
2559 RegCloseKey(hKey);
2560 return TRUE;
2563 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2565 IShellFolder *psfRoot, *psfDrives;
2566 IEnumIDList *lpeRoot, *lpeDrives;
2567 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2569 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2571 TRACE("\n");
2573 liInfos->iMaxIndentation = 0;
2575 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2577 /* set item height for both text field and listbox */
2578 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2579 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2581 /* Turn on the extended UI for the combo box like Windows does */
2582 CBSetExtendedUI(hwndCombo, TRUE);
2584 /* Initialise data of Desktop folder */
2585 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2586 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2587 COMDLG32_SHFree(pidlTmp);
2589 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2591 SHGetDesktopFolder(&psfRoot);
2593 if (psfRoot)
2595 /* enumerate the contents of the desktop */
2596 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2598 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2600 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2602 /* If the unixfs extension is rooted, we don't expand the drives by default */
2603 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2605 /* special handling for CSIDL_DRIVES */
2606 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2608 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2610 /* enumerate the drives */
2611 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2613 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2615 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2616 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2617 COMDLG32_SHFree(pidlAbsTmp);
2618 COMDLG32_SHFree(pidlTmp1);
2620 IEnumIDList_Release(lpeDrives);
2622 IShellFolder_Release(psfDrives);
2627 COMDLG32_SHFree(pidlTmp);
2629 IEnumIDList_Release(lpeRoot);
2631 IShellFolder_Release(psfRoot);
2634 COMDLG32_SHFree(pidlDrives);
2637 /***********************************************************************
2638 * FILEDLG95_LOOKIN_DrawItem
2640 * WM_DRAWITEM message handler
2642 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2644 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2645 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2646 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2647 RECT rectText;
2648 RECT rectIcon;
2649 SHFILEINFOA sfi;
2650 HIMAGELIST ilItemImage;
2651 int iIndentation;
2652 TEXTMETRICA tm;
2653 LPSFOLDER tmpFolder;
2656 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2658 TRACE("\n");
2660 if(pDIStruct->itemID == -1)
2661 return 0;
2663 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2664 pDIStruct->itemID)))
2665 return 0;
2668 if(pDIStruct->itemID == liInfos->uSelectedItem)
2670 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2672 &sfi,
2673 sizeof (SHFILEINFOA),
2674 SHGFI_PIDL | SHGFI_SMALLICON |
2675 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2676 SHGFI_DISPLAYNAME );
2678 else
2680 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2682 &sfi,
2683 sizeof (SHFILEINFOA),
2684 SHGFI_PIDL | SHGFI_SMALLICON |
2685 SHGFI_SYSICONINDEX |
2686 SHGFI_DISPLAYNAME);
2689 /* Is this item selected ? */
2690 if(pDIStruct->itemState & ODS_SELECTED)
2692 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2693 SetBkColor(pDIStruct->hDC,crHighLight);
2694 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2696 else
2698 SetTextColor(pDIStruct->hDC,crText);
2699 SetBkColor(pDIStruct->hDC,crWin);
2700 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2703 /* Do not indent item if drawing in the edit of the combo */
2704 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2706 iIndentation = 0;
2707 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2709 &sfi,
2710 sizeof (SHFILEINFOA),
2711 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2712 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2715 else
2717 iIndentation = tmpFolder->m_iIndent;
2719 /* Draw text and icon */
2721 /* Initialise the icon display area */
2722 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2723 rectIcon.top = pDIStruct->rcItem.top;
2724 rectIcon.right = rectIcon.left + ICONWIDTH;
2725 rectIcon.bottom = pDIStruct->rcItem.bottom;
2727 /* Initialise the text display area */
2728 GetTextMetricsA(pDIStruct->hDC, &tm);
2729 rectText.left = rectIcon.right;
2730 rectText.top =
2731 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2732 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2733 rectText.bottom =
2734 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2736 /* Draw the icon from the image list */
2737 ImageList_Draw(ilItemImage,
2738 sfi.iIcon,
2739 pDIStruct->hDC,
2740 rectIcon.left,
2741 rectIcon.top,
2742 ILD_TRANSPARENT );
2744 /* Draw the associated text */
2745 if(sfi.szDisplayName)
2746 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2749 return NOERROR;
2752 /***********************************************************************
2753 * FILEDLG95_LOOKIN_OnCommand
2755 * LookIn combo box WM_COMMAND message handler
2756 * If the function succeeds, the return value is nonzero.
2758 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2760 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2762 TRACE("%p\n", fodInfos);
2764 switch(wNotifyCode)
2766 case CBN_SELENDOK:
2768 LPSFOLDER tmpFolder;
2769 int iItem;
2771 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2773 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2774 iItem)))
2775 return FALSE;
2778 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2779 tmpFolder->pidlItem,
2780 SBSP_ABSOLUTE)))
2782 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2783 return TRUE;
2785 break;
2789 return FALSE;
2792 /***********************************************************************
2793 * FILEDLG95_LOOKIN_AddItem
2795 * Adds an absolute pidl item to the lookin combo box
2796 * returns the index of the inserted item
2798 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2800 LPITEMIDLIST pidlNext;
2801 SHFILEINFOA sfi;
2802 SFOLDER *tmpFolder;
2803 LookInInfos *liInfos;
2805 TRACE("%08x\n", iInsertId);
2807 if(!pidl)
2808 return -1;
2810 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2811 return -1;
2813 tmpFolder = MemAlloc(sizeof(SFOLDER));
2814 tmpFolder->m_iIndent = 0;
2816 /* Calculate the indentation of the item in the lookin*/
2817 pidlNext = pidl;
2818 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2820 tmpFolder->m_iIndent++;
2823 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2825 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2826 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2828 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2829 SHGetFileInfoA((LPSTR)pidl,
2831 &sfi,
2832 sizeof(sfi),
2833 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2834 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2836 TRACE("-- Add %s attr=%08x\n", sfi.szDisplayName, sfi.dwAttributes);
2838 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2840 int iItemID;
2842 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2844 /* Add the item at the end of the list */
2845 if(iInsertId < 0)
2847 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2849 /* Insert the item at the iInsertId position*/
2850 else
2852 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2855 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2856 return iItemID;
2859 COMDLG32_SHFree( tmpFolder->pidlItem );
2860 MemFree( tmpFolder );
2861 return -1;
2865 /***********************************************************************
2866 * FILEDLG95_LOOKIN_InsertItemAfterParent
2868 * Insert an item below its parent
2870 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2873 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2874 int iParentPos;
2876 TRACE("\n");
2878 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2880 if(iParentPos < 0)
2882 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2885 /* Free pidlParent memory */
2886 COMDLG32_SHFree((LPVOID)pidlParent);
2888 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2891 /***********************************************************************
2892 * FILEDLG95_LOOKIN_SelectItem
2894 * Adds an absolute pidl item to the lookin combo box
2895 * returns the index of the inserted item
2897 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2899 int iItemPos;
2900 LookInInfos *liInfos;
2902 TRACE("\n");
2904 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2906 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2908 if(iItemPos < 0)
2910 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2911 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2914 else
2916 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2917 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2919 int iRemovedItem;
2921 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2922 break;
2923 if(iRemovedItem < iItemPos)
2924 iItemPos--;
2928 CBSetCurSel(hwnd,iItemPos);
2929 liInfos->uSelectedItem = iItemPos;
2931 return 0;
2935 /***********************************************************************
2936 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2938 * Remove the item with an expansion level over iExpansionLevel
2940 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2942 int iItemPos;
2944 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2946 TRACE("\n");
2948 if(liInfos->iMaxIndentation <= 2)
2949 return -1;
2951 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2953 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2954 COMDLG32_SHFree(tmpFolder->pidlItem);
2955 MemFree(tmpFolder);
2956 CBDeleteString(hwnd,iItemPos);
2957 liInfos->iMaxIndentation--;
2959 return iItemPos;
2962 return -1;
2965 /***********************************************************************
2966 * FILEDLG95_LOOKIN_SearchItem
2968 * Search for pidl in the lookin combo box
2969 * returns the index of the found item
2971 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2973 int i = 0;
2974 int iCount = CBGetCount(hwnd);
2976 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2978 if (iCount != CB_ERR)
2980 for(;i<iCount;i++)
2982 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2984 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2985 return i;
2986 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2987 return i;
2991 return -1;
2994 /***********************************************************************
2995 * FILEDLG95_LOOKIN_Clean
2997 * Clean the memory used by the lookin combo box
2999 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3001 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3002 int iPos;
3003 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3005 TRACE("\n");
3007 /* Delete each string of the combo and their associated data */
3008 if (iCount != CB_ERR)
3010 for(iPos = iCount-1;iPos>=0;iPos--)
3012 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3013 COMDLG32_SHFree(tmpFolder->pidlItem);
3014 MemFree(tmpFolder);
3015 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3019 /* LookInInfos structure */
3020 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3023 /***********************************************************************
3024 * FILEDLG95_FILENAME_FillFromSelection
3026 * fills the edit box from the cached DataObject
3028 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3030 FileOpenDlgInfos *fodInfos;
3031 LPITEMIDLIST pidl;
3032 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3033 char lpstrTemp[MAX_PATH];
3034 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
3036 TRACE("\n");
3037 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3039 /* Count how many files we have */
3040 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3042 /* calculate the string length, count files */
3043 if (nFileSelected >= 1)
3045 nLength += 3; /* first and last quotes, trailing \0 */
3046 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3048 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3050 if (pidl)
3052 /* get the total length of the selected file names */
3053 lpstrTemp[0] = '\0';
3054 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3056 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3058 nLength += strlen( lpstrTemp ) + 3;
3059 nFiles++;
3061 COMDLG32_SHFree( pidl );
3066 /* allocate the buffer */
3067 if (nFiles <= 1) nLength = MAX_PATH;
3068 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
3069 lpstrAllFile[0] = '\0';
3071 /* Generate the string for the edit control */
3072 if(nFiles >= 1)
3074 lpstrCurrFile = lpstrAllFile;
3075 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3077 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3079 if (pidl)
3081 /* get the file name */
3082 lpstrTemp[0] = '\0';
3083 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3085 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3087 if ( nFiles > 1)
3089 *lpstrCurrFile++ = '\"';
3090 strcpy( lpstrCurrFile, lpstrTemp );
3091 lpstrCurrFile += strlen( lpstrTemp );
3092 strcpy( lpstrCurrFile, "\" " );
3093 lpstrCurrFile += 2;
3095 else
3097 strcpy( lpstrAllFile, lpstrTemp );
3100 COMDLG32_SHFree( (LPVOID) pidl );
3103 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3105 /* Select the file name like Windows does */
3106 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
3108 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3112 /* copied from shell32 to avoid linking to it
3113 * FIXME: why? shell32 is already linked
3115 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3117 switch (src->uType)
3119 case STRRET_WSTR:
3120 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
3121 COMDLG32_SHFree(src->u.pOleStr);
3122 break;
3124 case STRRET_CSTR:
3125 lstrcpynA((LPSTR)dest, src->u.cStr, len);
3126 break;
3128 case STRRET_OFFSET:
3129 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
3130 break;
3132 default:
3133 FIXME("unknown type!\n");
3134 if (len)
3136 *(LPSTR)dest = '\0';
3138 return(E_FAIL);
3140 return S_OK;
3143 /***********************************************************************
3144 * FILEDLG95_FILENAME_GetFileNames
3146 * Copies the filenames to a delimited string list.
3147 * The delimiter is specified by the parameter 'separator',
3148 * usually either a space or a nul
3150 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3152 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3153 UINT nStrCharCount = 0; /* index in src buffer */
3154 UINT nFileIndex = 0; /* index in dest buffer */
3155 UINT nFileCount = 0; /* number of files */
3156 UINT nStrLen = 0; /* length of string in edit control */
3157 LPWSTR lpstrEdit; /* buffer for string from edit control */
3159 TRACE("\n");
3161 /* get the filenames from the edit control */
3162 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3163 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3164 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3166 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3168 /* we might get single filename without any '"',
3169 * so we need nStrLen + terminating \0 + end-of-list \0 */
3170 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3171 *sizeUsed = 0;
3173 /* build delimited file list from filenames */
3174 while ( nStrCharCount <= nStrLen )
3176 if ( lpstrEdit[nStrCharCount]=='"' )
3178 nStrCharCount++;
3179 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3181 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3182 (*sizeUsed)++;
3183 nStrCharCount++;
3185 (*lpstrFileList)[nFileIndex++] = separator;
3186 (*sizeUsed)++;
3187 nFileCount++;
3189 nStrCharCount++;
3192 /* single, unquoted string */
3193 if ((nStrLen > 0) && (*sizeUsed == 0) )
3195 strcpyW(*lpstrFileList, lpstrEdit);
3196 nFileIndex = strlenW(lpstrEdit) + 1;
3197 (*sizeUsed) = nFileIndex;
3198 nFileCount = 1;
3201 /* trailing \0 */
3202 (*lpstrFileList)[nFileIndex] = '\0';
3203 (*sizeUsed)++;
3205 MemFree(lpstrEdit);
3206 return nFileCount;
3209 #define SETDefFormatEtc(fe,cf,med) \
3211 (fe).cfFormat = cf;\
3212 (fe).dwAspect = DVASPECT_CONTENT; \
3213 (fe).ptd =NULL;\
3214 (fe).tymed = med;\
3215 (fe).lindex = -1;\
3219 * DATAOBJECT Helper functions
3222 /***********************************************************************
3223 * COMCTL32_ReleaseStgMedium
3225 * like ReleaseStgMedium from ole32
3227 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3229 if(medium.pUnkForRelease)
3231 IUnknown_Release(medium.pUnkForRelease);
3233 else
3235 GlobalUnlock(medium.u.hGlobal);
3236 GlobalFree(medium.u.hGlobal);
3240 /***********************************************************************
3241 * GetPidlFromDataObject
3243 * Return pidl(s) by number from the cached DataObject
3245 * nPidlIndex=0 gets the fully qualified root path
3247 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3250 STGMEDIUM medium;
3251 FORMATETC formatetc;
3252 LPITEMIDLIST pidl = NULL;
3254 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3256 if (!doSelected)
3257 return NULL;
3259 /* Set the FORMATETC structure*/
3260 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3262 /* Get the pidls from IDataObject */
3263 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3265 LPIDA cida = GlobalLock(medium.u.hGlobal);
3266 if(nPidlIndex <= cida->cidl)
3268 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3270 COMCTL32_ReleaseStgMedium(medium);
3272 return pidl;
3275 /***********************************************************************
3276 * GetNumSelected
3278 * Return the number of selected items in the DataObject.
3281 UINT GetNumSelected( IDataObject *doSelected )
3283 UINT retVal = 0;
3284 STGMEDIUM medium;
3285 FORMATETC formatetc;
3287 TRACE("sv=%p\n", doSelected);
3289 if (!doSelected) return 0;
3291 /* Set the FORMATETC structure*/
3292 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3294 /* Get the pidls from IDataObject */
3295 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3297 LPIDA cida = GlobalLock(medium.u.hGlobal);
3298 retVal = cida->cidl;
3299 COMCTL32_ReleaseStgMedium(medium);
3300 return retVal;
3302 return 0;
3306 * TOOLS
3309 /***********************************************************************
3310 * GetName
3312 * Get the pidl's display name (relative to folder) and
3313 * put it in lpstrFileName.
3315 * Return NOERROR on success,
3316 * E_FAIL otherwise
3319 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3321 STRRET str;
3322 HRESULT hRes;
3324 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3326 if(!lpsf)
3328 SHGetDesktopFolder(&lpsf);
3329 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3330 IShellFolder_Release(lpsf);
3331 return hRes;
3334 /* Get the display name of the pidl relative to the folder */
3335 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3337 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3339 return E_FAIL;
3342 /***********************************************************************
3343 * GetShellFolderFromPidl
3345 * pidlRel is the item pidl relative
3346 * Return the IShellFolder of the absolute pidl
3348 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3350 IShellFolder *psf = NULL,*psfParent;
3352 TRACE("%p\n", pidlAbs);
3354 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3356 psf = psfParent;
3357 if(pidlAbs && pidlAbs->mkid.cb)
3359 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3361 IShellFolder_Release(psfParent);
3362 return psf;
3365 /* return the desktop */
3366 return psfParent;
3368 return NULL;
3371 /***********************************************************************
3372 * GetParentPidl
3374 * Return the LPITEMIDLIST to the parent of the pidl in the list
3376 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3378 LPITEMIDLIST pidlParent;
3380 TRACE("%p\n", pidl);
3382 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3383 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3385 return pidlParent;
3388 /***********************************************************************
3389 * GetPidlFromName
3391 * returns the pidl of the file name relative to folder
3392 * NULL if an error occurred
3394 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3396 LPITEMIDLIST pidl = NULL;
3397 ULONG ulEaten;
3399 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3401 if(!lpcstrFileName) return NULL;
3402 if(!*lpcstrFileName) return NULL;
3404 if(!lpsf)
3406 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3407 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3408 IShellFolder_Release(lpsf);
3411 else
3413 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3415 return pidl;
3420 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3422 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3423 HRESULT ret;
3425 TRACE("%p, %p\n", psf, pidl);
3427 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3429 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3430 /* see documentation shell 4.1*/
3431 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3434 /***********************************************************************
3435 * BrowseSelectedFolder
3437 static BOOL BrowseSelectedFolder(HWND hwnd)
3439 BOOL bBrowseSelFolder = FALSE;
3440 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3442 TRACE("\n");
3444 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3446 LPITEMIDLIST pidlSelection;
3448 /* get the file selected */
3449 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3450 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3452 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3453 pidlSelection, SBSP_RELATIVE ) ) )
3455 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3456 ' ','n','o','t',' ','e','x','i','s','t',0};
3457 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3459 bBrowseSelFolder = TRUE;
3460 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3462 COMDLG32_SHFree( pidlSelection );
3465 return bBrowseSelFolder;
3469 * Memory allocation methods */
3470 static void *MemAlloc(UINT size)
3472 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3475 static void MemFree(void *mem)
3477 HeapFree(GetProcessHeap(),0,mem);
3481 * Old-style (win3.1) dialogs */
3483 /***********************************************************************
3484 * FD32_GetTemplate [internal]
3486 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3487 * by a 32 bits application
3490 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3492 LPOPENFILENAMEW ofnW = lfs->ofnW;
3493 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3494 HANDLE hDlgTmpl;
3496 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3498 if (!(lfs->template = LockResource( ofnW->hInstance )))
3500 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3501 return FALSE;
3504 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3506 HRSRC hResInfo;
3507 if (priv->ofnA)
3508 hResInfo = FindResourceA(priv->ofnA->hInstance,
3509 priv->ofnA->lpTemplateName,
3510 (LPSTR)RT_DIALOG);
3511 else
3512 hResInfo = FindResourceW(ofnW->hInstance,
3513 ofnW->lpTemplateName,
3514 (LPWSTR)RT_DIALOG);
3515 if (!hResInfo)
3517 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3518 return FALSE;
3520 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3521 hResInfo)) ||
3522 !(lfs->template = LockResource(hDlgTmpl)))
3524 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3525 return FALSE;
3527 } else { /* get it from internal Wine resource */
3528 HRSRC hResInfo;
3529 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3530 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3532 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3533 return FALSE;
3535 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3536 !(lfs->template = LockResource( hDlgTmpl )))
3538 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3539 return FALSE;
3542 return TRUE;
3546 /************************************************************************
3547 * FD32_Init [internal]
3548 * called from the common 16/32 code to initialize 32 bit data
3550 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3552 BOOL IsUnicode = (BOOL) data;
3553 PFD32_PRIVATE priv;
3555 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3556 lfs->private1632 = priv;
3557 if (NULL == lfs->private1632) return FALSE;
3558 if (IsUnicode)
3560 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3561 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3562 if (lfs->ofnW->lpfnHook)
3563 lfs->hook = TRUE;
3565 else
3567 priv->ofnA = (LPOPENFILENAMEA) lParam;
3568 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3569 if (priv->ofnA->lpfnHook)
3570 lfs->hook = TRUE;
3571 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3572 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3575 if (! FD32_GetTemplate(lfs)) return FALSE;
3577 return TRUE;
3580 /***********************************************************************
3581 * FD32_CallWindowProc [internal]
3583 * called from the common 16/32 code to call the appropriate hook
3585 static BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
3586 LPARAM lParam)
3588 BOOL ret;
3589 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3591 if (priv->ofnA)
3593 TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3594 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3595 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3596 TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3597 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3598 return ret;
3601 TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3602 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3603 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3604 TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3605 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3606 return ret;
3609 /***********************************************************************
3610 * FD32_UpdateResult [internal]
3611 * update the real client structures if any
3613 static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs)
3615 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3616 LPOPENFILENAMEW ofnW = lfs->ofnW;
3618 if (priv->ofnA)
3620 if (ofnW->nMaxFile &&
3621 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3622 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3623 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3624 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3625 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3629 /***********************************************************************
3630 * FD32_UpdateFileTitle [internal]
3631 * update the real client structures if any
3633 static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs)
3635 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3636 LPOPENFILENAMEW ofnW = lfs->ofnW;
3638 if (priv->ofnA)
3640 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3641 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3642 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3647 /***********************************************************************
3648 * FD32_SendLbGetCurSel [internal]
3649 * retrieve selected listbox item
3651 static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs)
3653 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3657 /************************************************************************
3658 * FD32_Destroy [internal]
3659 * called from the common 16/32 code to cleanup 32 bit data
3661 static void CALLBACK FD32_Destroy(PFD31_DATA lfs)
3663 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3665 /* if ofnW has been allocated, have to free everything in it */
3666 if (NULL != priv && NULL != priv->ofnA)
3668 FD31_FreeOfnW(lfs->ofnW);
3669 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3673 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3675 callbacks->Init = FD32_Init;
3676 callbacks->CWP = FD32_CallWindowProc;
3677 callbacks->UpdateResult = FD32_UpdateResult;
3678 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3679 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3680 callbacks->Destroy = FD32_Destroy;
3683 /***********************************************************************
3684 * FD32_WMMeasureItem [internal]
3686 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3688 LPMEASUREITEMSTRUCT lpmeasure;
3690 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3691 lpmeasure->itemHeight = FD31_GetFldrHeight();
3692 return TRUE;
3696 /***********************************************************************
3697 * FileOpenDlgProc [internal]
3698 * Used for open and save, in fact.
3700 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3701 WPARAM wParam, LPARAM lParam)
3703 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3705 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
3706 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3708 INT_PTR lRet;
3709 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3710 if (lRet)
3711 return lRet; /* else continue message processing */
3713 switch (wMsg)
3715 case WM_INITDIALOG:
3716 return FD31_WMInitDialog(hWnd, wParam, lParam);
3718 case WM_MEASUREITEM:
3719 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3721 case WM_DRAWITEM:
3722 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3724 case WM_COMMAND:
3725 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3726 #if 0
3727 case WM_CTLCOLOR:
3728 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3729 switch (HIWORD(lParam))
3731 case CTLCOLOR_BTN:
3732 SetTextColor((HDC16)wParam, 0x00000000);
3733 return hGRAYBrush;
3734 case CTLCOLOR_STATIC:
3735 SetTextColor((HDC16)wParam, 0x00000000);
3736 return hGRAYBrush;
3738 break;
3739 #endif
3741 return FALSE;
3745 /***********************************************************************
3746 * GetFileName31A [internal]
3748 * Creates a win31 style dialog box for the user to select a file to open/save.
3750 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3751 UINT dlgType /* type dialogue : open/save */
3754 HINSTANCE hInst;
3755 BOOL bRet = FALSE;
3756 PFD31_DATA lfs;
3757 FD31_CALLBACKS callbacks;
3759 if (!lpofn || !FD31_Init()) return FALSE;
3761 TRACE("ofn flags %08x\n", lpofn->Flags);
3762 FD32_SetupCallbacks(&callbacks);
3763 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3764 if (lfs)
3766 hInst = (HINSTANCE)GetWindowLongPtrA( lpofn->hwndOwner, GWLP_HINSTANCE );
3767 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3768 FD32_FileOpenDlgProc, (LPARAM)lfs);
3769 FD31_DestroyPrivate(lfs);
3772 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3773 return bRet;
3776 /***********************************************************************
3777 * GetFileName31W [internal]
3779 * Creates a win31 style dialog box for the user to select a file to open/save
3781 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3782 UINT dlgType /* type dialogue : open/save */
3785 HINSTANCE hInst;
3786 BOOL bRet = FALSE;
3787 PFD31_DATA lfs;
3788 FD31_CALLBACKS callbacks;
3790 if (!lpofn || !FD31_Init()) return FALSE;
3792 FD32_SetupCallbacks(&callbacks);
3793 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3794 if (lfs)
3796 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3797 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3798 FD32_FileOpenDlgProc, (LPARAM)lfs);
3799 FD31_DestroyPrivate(lfs);
3802 TRACE("file %s, file offset %d, ext offset %d\n",
3803 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3804 return bRet;
3807 /* ------------------ APIs ---------------------- */
3809 /***********************************************************************
3810 * GetOpenFileNameA (COMDLG32.@)
3812 * Creates a dialog box for the user to select a file to open.
3814 * RETURNS
3815 * TRUE on success: user enters a valid file
3816 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3819 BOOL WINAPI GetOpenFileNameA(
3820 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3822 BOOL win16look = FALSE;
3824 TRACE("flags %08x\n", ofn->Flags);
3826 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3827 if (ofn->Flags & OFN_FILEMUSTEXIST)
3828 ofn->Flags |= OFN_PATHMUSTEXIST;
3830 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3831 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3833 if (win16look)
3834 return GetFileName31A(ofn, OPEN_DIALOG);
3835 else
3836 return GetFileDialog95A(ofn, OPEN_DIALOG);
3839 /***********************************************************************
3840 * GetOpenFileNameW (COMDLG32.@)
3842 * Creates a dialog box for the user to select a file to open.
3844 * RETURNS
3845 * TRUE on success: user enters a valid file
3846 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3849 BOOL WINAPI GetOpenFileNameW(
3850 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3852 BOOL win16look = FALSE;
3854 TRACE("flags %08x\n", ofn->Flags);
3856 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3857 if (ofn->Flags & OFN_FILEMUSTEXIST)
3858 ofn->Flags |= OFN_PATHMUSTEXIST;
3860 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3861 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3863 if (win16look)
3864 return GetFileName31W(ofn, OPEN_DIALOG);
3865 else
3866 return GetFileDialog95W(ofn, OPEN_DIALOG);
3870 /***********************************************************************
3871 * GetSaveFileNameA (COMDLG32.@)
3873 * Creates a dialog box for the user to select a file to save.
3875 * RETURNS
3876 * TRUE on success: user enters a valid file
3877 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3880 BOOL WINAPI GetSaveFileNameA(
3881 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3883 BOOL win16look = FALSE;
3885 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3886 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3888 if (win16look)
3889 return GetFileName31A(ofn, SAVE_DIALOG);
3890 else
3891 return GetFileDialog95A(ofn, SAVE_DIALOG);
3894 /***********************************************************************
3895 * GetSaveFileNameW (COMDLG32.@)
3897 * Creates a dialog box for the user to select a file to save.
3899 * RETURNS
3900 * TRUE on success: user enters a valid file
3901 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3904 BOOL WINAPI GetSaveFileNameW(
3905 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3907 BOOL win16look = FALSE;
3909 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3910 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3912 if (win16look)
3913 return GetFileName31W(ofn, SAVE_DIALOG);
3914 else
3915 return GetFileDialog95W(ofn, SAVE_DIALOG);
3918 /***********************************************************************
3919 * GetFileTitleA (COMDLG32.@)
3921 * See GetFileTitleW.
3923 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
3925 int ret;
3926 UNICODE_STRING strWFile;
3927 LPWSTR lpWTitle;
3929 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
3930 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
3931 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
3932 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
3933 RtlFreeUnicodeString( &strWFile );
3934 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
3935 return ret;
3939 /***********************************************************************
3940 * GetFileTitleW (COMDLG32.@)
3942 * Get the name of a file.
3944 * PARAMS
3945 * lpFile [I] name and location of file
3946 * lpTitle [O] returned file name
3947 * cbBuf [I] buffer size of lpTitle
3949 * RETURNS
3950 * Success: zero
3951 * Failure: negative number.
3953 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
3955 int i, len;
3956 static const WCHAR brkpoint[] = {'*','[',']',0};
3957 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
3959 if(lpFile == NULL || lpTitle == NULL)
3960 return -1;
3962 len = strlenW(lpFile);
3964 if (len == 0)
3965 return -1;
3967 if(strpbrkW(lpFile, brkpoint))
3968 return -1;
3970 len--;
3972 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
3973 return -1;
3975 for(i = len; i >= 0; i--)
3977 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
3979 i++;
3980 break;
3984 if(i == -1)
3985 i++;
3987 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
3989 len = strlenW(lpFile+i)+1;
3990 if(cbBuf < len)
3991 return len;
3993 strcpyW(lpTitle, &lpFile[i]);
3994 return 0;