ntoskrnl.exe: Implemented IoCreateDevice and IoDeleteDevice.
[wine/wine64.git] / dlls / comdlg32 / filedlg.c
blob68b6b601d77d45bfb0a8d91eccbf219a6f11d072
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 "wingdi.h"
68 #include "winuser.h"
69 #include "winreg.h"
70 #include "commdlg.h"
71 #include "dlgs.h"
72 #include "cdlg.h"
73 #include "filedlg31.h"
74 #include "cderr.h"
75 #include "shellapi.h"
76 #include "shlobj.h"
77 #include "filedlgbrowser.h"
78 #include "shlwapi.h"
80 #include "wine/unicode.h"
81 #include "wine/debug.h"
83 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
85 #define UNIMPLEMENTED_FLAGS \
86 (OFN_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 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
145 #define CBInsertString(hwnd,str,pos) \
146 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
148 #define CBDeleteString(hwnd,pos) \
149 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
151 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
152 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
154 #define CBGetItemDataPtr(hwnd,iItemId) \
155 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
157 #define CBGetLBText(hwnd,iItemId,str) \
158 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
160 #define CBGetCurSel(hwnd) \
161 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
163 #define CBSetCurSel(hwnd,pos) \
164 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
166 #define CBGetCount(hwnd) \
167 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
168 #define CBShowDropDown(hwnd,show) \
169 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
170 #define CBSetItemHeight(hwnd,index,height) \
171 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
173 #define CBSetExtendedUI(hwnd,flag) \
174 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
176 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
177 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
179 /***********************************************************************
180 * Prototypes
183 /* Internal functions used by the dialog */
184 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
185 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
186 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
187 static BOOL FILEDLG95_OnOpen(HWND hwnd);
188 static LRESULT FILEDLG95_InitControls(HWND hwnd);
189 static void FILEDLG95_Clean(HWND hwnd);
191 /* Functions used by the shell navigation */
192 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
193 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
194 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
195 static void FILEDLG95_SHELL_Clean(HWND hwnd);
196 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
198 /* Functions used by the EDIT box */
199 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator);
201 /* Functions used by the filetype combo box */
202 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
203 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
204 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
205 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
207 /* Functions used by the Look In combo box */
208 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
209 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
210 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
211 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
212 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
213 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
214 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
215 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
216 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
218 /* Miscellaneous tool functions */
219 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
220 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
221 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
222 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
224 /* Shell memory allocation */
225 static void *MemAlloc(UINT size);
226 static void MemFree(void *mem);
228 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
229 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
230 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
231 static BOOL BrowseSelectedFolder(HWND hwnd);
233 /***********************************************************************
234 * GetFileName95
236 * Creates an Open common dialog box that lets the user select
237 * the drive, directory, and the name of a file or set of files to open.
239 * IN : The FileOpenDlgInfos structure associated with the dialog
240 * OUT : TRUE on success
241 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
243 static BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
246 LRESULT lRes;
247 LPCVOID template;
248 HRSRC hRes;
249 HANDLE hDlgTmpl = 0;
250 HRESULT hr;
252 /* test for missing functionality */
253 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
255 FIXME("Flags 0x%08x not yet implemented\n",
256 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
259 /* Create the dialog from a template */
261 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
263 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
264 return FALSE;
266 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
267 !(template = LockResource( hDlgTmpl )))
269 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
270 return FALSE;
273 /* old style hook messages */
274 if (IsHooked(fodInfos))
276 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
277 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
278 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
279 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
282 /* Some shell namespace extensions depend on COM being initialized. */
283 hr = OleInitialize(NULL);
285 if (fodInfos->unicode)
286 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
287 template,
288 fodInfos->ofnInfos->hwndOwner,
289 FileOpenDlgProc95,
290 (LPARAM) fodInfos);
291 else
292 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
293 (LPCDLGTEMPLATEA) template,
294 fodInfos->ofnInfos->hwndOwner,
295 FileOpenDlgProc95,
296 (LPARAM) fodInfos);
297 if (SUCCEEDED(hr))
298 OleUninitialize();
300 /* Unable to create the dialog */
301 if( lRes == -1)
302 return FALSE;
304 return lRes;
307 /***********************************************************************
308 * GetFileDialog95A
310 * Call GetFileName95 with this structure and clean the memory.
312 * IN : The OPENFILENAMEA initialisation structure passed to
313 * GetOpenFileNameA win api function (see filedlg.c)
315 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
317 BOOL ret;
318 FileOpenDlgInfos fodInfos;
319 LPSTR lpstrSavDir = NULL;
320 LPWSTR title = NULL;
321 LPWSTR defext = NULL;
322 LPWSTR filter = NULL;
323 LPWSTR customfilter = NULL;
325 /* Initialize CommDlgExtendedError() */
326 COMDLG32_SetCommDlgExtendedError(0);
328 /* Initialize FileOpenDlgInfos structure */
329 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
331 /* Pass in the original ofn */
332 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
334 /* save current directory */
335 if (ofn->Flags & OFN_NOCHANGEDIR)
337 lpstrSavDir = MemAlloc(MAX_PATH);
338 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
341 fodInfos.unicode = FALSE;
343 /* convert all the input strings to unicode */
344 if(ofn->lpstrInitialDir)
346 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
347 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
348 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
350 else
351 fodInfos.initdir = NULL;
353 if(ofn->lpstrFile)
355 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
356 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
358 else
359 fodInfos.filename = NULL;
361 if(ofn->lpstrDefExt)
363 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
364 defext = MemAlloc((len+1)*sizeof(WCHAR));
365 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
367 fodInfos.defext = defext;
369 if(ofn->lpstrTitle)
371 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
372 title = MemAlloc((len+1)*sizeof(WCHAR));
373 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
375 fodInfos.title = title;
377 if (ofn->lpstrFilter)
379 LPCSTR s;
380 int n, len;
382 /* filter is a list... title\0ext\0......\0\0 */
383 s = ofn->lpstrFilter;
384 while (*s) s = s+strlen(s)+1;
385 s++;
386 n = s - ofn->lpstrFilter;
387 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
388 filter = MemAlloc(len*sizeof(WCHAR));
389 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
391 fodInfos.filter = filter;
393 /* convert lpstrCustomFilter */
394 if (ofn->lpstrCustomFilter)
396 LPCSTR s;
397 int n, len;
399 /* customfilter contains a pair of strings... title\0ext\0 */
400 s = ofn->lpstrCustomFilter;
401 if (*s) s = s+strlen(s)+1;
402 if (*s) s = s+strlen(s)+1;
403 n = s - ofn->lpstrCustomFilter;
404 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
405 customfilter = MemAlloc(len*sizeof(WCHAR));
406 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
408 fodInfos.customfilter = customfilter;
410 /* Initialize the dialog property */
411 fodInfos.DlgInfos.dwDlgProp = 0;
412 fodInfos.DlgInfos.hwndCustomDlg = NULL;
414 switch(iDlgType)
416 case OPEN_DIALOG :
417 ret = GetFileName95(&fodInfos);
418 break;
419 case SAVE_DIALOG :
420 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
421 ret = GetFileName95(&fodInfos);
422 break;
423 default :
424 ret = 0;
427 if (lpstrSavDir)
429 SetCurrentDirectoryA(lpstrSavDir);
430 MemFree(lpstrSavDir);
433 MemFree(title);
434 MemFree(defext);
435 MemFree(filter);
436 MemFree(customfilter);
437 MemFree(fodInfos.initdir);
438 MemFree(fodInfos.filename);
440 TRACE("selected file: %s\n",ofn->lpstrFile);
442 return ret;
445 /***********************************************************************
446 * GetFileDialog95W
448 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
449 * Call GetFileName95 with this structure and clean the memory.
452 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
454 BOOL ret;
455 FileOpenDlgInfos fodInfos;
456 LPWSTR lpstrSavDir = NULL;
458 /* Initialize CommDlgExtendedError() */
459 COMDLG32_SetCommDlgExtendedError(0);
461 /* Initialize FileOpenDlgInfos structure */
462 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
464 /* Pass in the original ofn */
465 fodInfos.ofnInfos = ofn;
467 fodInfos.title = ofn->lpstrTitle;
468 fodInfos.defext = ofn->lpstrDefExt;
469 fodInfos.filter = ofn->lpstrFilter;
470 fodInfos.customfilter = ofn->lpstrCustomFilter;
472 /* convert string arguments, save others */
473 if(ofn->lpstrFile)
475 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
476 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
478 else
479 fodInfos.filename = NULL;
481 if(ofn->lpstrInitialDir)
483 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
484 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
485 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
486 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
488 else
489 fodInfos.initdir = NULL;
491 /* save current directory */
492 if (ofn->Flags & OFN_NOCHANGEDIR)
494 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
495 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
498 fodInfos.unicode = TRUE;
500 switch(iDlgType)
502 case OPEN_DIALOG :
503 ret = GetFileName95(&fodInfos);
504 break;
505 case SAVE_DIALOG :
506 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
507 ret = GetFileName95(&fodInfos);
508 break;
509 default :
510 ret = 0;
513 if (lpstrSavDir)
515 SetCurrentDirectoryW(lpstrSavDir);
516 MemFree(lpstrSavDir);
519 /* restore saved IN arguments and convert OUT arguments back */
520 MemFree(fodInfos.filename);
521 MemFree(fodInfos.initdir);
522 return ret;
525 /******************************************************************************
526 * COMDLG32_GetDisplayNameOf [internal]
528 * Helper function to get the display name for a pidl.
530 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
531 LPSHELLFOLDER psfDesktop;
532 STRRET strret;
534 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
535 return FALSE;
537 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
538 IShellFolder_Release(psfDesktop);
539 return FALSE;
542 IShellFolder_Release(psfDesktop);
543 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
546 /***********************************************************************
547 * ArrangeCtrlPositions [internal]
549 * NOTE: Do not change anything here without a lot of testing.
551 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
553 HWND hwndChild, hwndStc32;
554 RECT rectParent, rectChild, rectStc32;
555 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
557 /* Take into account if open as read only checkbox and help button
558 * are hidden
560 if (hide_help)
562 RECT rectHelp, rectCancel;
563 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
564 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
565 /* subtract the height of the help button plus the space between
566 * the help button and the cancel button to the height of the dialog
568 help_fixup = rectHelp.bottom - rectCancel.bottom;
572 There are two possibilities to add components to the default file dialog box.
574 By default, all the new components are added below the standard dialog box (the else case).
576 However, if there is a static text component with the stc32 id, a special case happens.
577 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
578 in the window and the cx and cy indicate how to size the window.
579 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
580 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
584 GetClientRect(hwndParentDlg, &rectParent);
586 /* when arranging controls we have to use fixed parent size */
587 rectParent.bottom -= help_fixup;
589 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
590 if (hwndStc32)
592 GetWindowRect(hwndStc32, &rectStc32);
593 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
595 /* set the size of the stc32 control according to the size of
596 * client area of the parent dialog
598 SetWindowPos(hwndStc32, 0,
599 0, 0,
600 rectParent.right, rectParent.bottom,
601 SWP_NOMOVE | SWP_NOZORDER);
603 else
604 SetRectEmpty(&rectStc32);
606 /* this part moves controls of the child dialog */
607 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
608 while (hwndChild)
610 if (hwndChild != hwndStc32)
612 GetWindowRect(hwndChild, &rectChild);
613 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
615 /* move only if stc32 exist */
616 if (hwndStc32 && rectChild.left > rectStc32.right)
618 LONG old_left = rectChild.left;
620 /* move to the right of visible controls of the parent dialog */
621 rectChild.left += rectParent.right;
622 rectChild.left -= rectStc32.right;
624 child_width_fixup = rectChild.left - old_left;
626 /* move even if stc32 doesn't exist */
627 if (rectChild.top >= rectStc32.bottom)
629 LONG old_top = rectChild.top;
631 /* move below visible controls of the parent dialog */
632 rectChild.top += rectParent.bottom;
633 rectChild.top -= rectStc32.bottom - rectStc32.top;
635 child_height_fixup = rectChild.top - old_top;
638 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
639 0, 0, SWP_NOSIZE | SWP_NOZORDER);
641 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
644 /* this part moves controls of the parent dialog */
645 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
646 while (hwndChild)
648 if (hwndChild != hwndChildDlg)
650 GetWindowRect(hwndChild, &rectChild);
651 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
653 /* left,top of stc32 marks the position of controls
654 * from the parent dialog
656 rectChild.left += rectStc32.left;
657 rectChild.top += rectStc32.top;
659 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
660 0, 0, SWP_NOSIZE | SWP_NOZORDER);
662 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
665 /* calculate the size of the resulting dialog */
667 /* here we have to use original parent size */
668 GetClientRect(hwndParentDlg, &rectParent);
669 GetClientRect(hwndChildDlg, &rectChild);
671 if (hwndStc32)
673 rectChild.right += child_width_fixup;
674 rectChild.bottom += child_height_fixup;
676 if (rectParent.right > rectChild.right)
678 rectParent.right += rectChild.right;
679 rectParent.right -= rectStc32.right - rectStc32.left;
681 else
683 rectParent.right = rectChild.right;
686 if (rectParent.bottom > rectChild.bottom)
688 rectParent.bottom += rectChild.bottom;
689 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
691 else
693 /* child dialog is higher, unconditionally set new dialog
694 * height to its size (help_fixup will be subtracted below)
696 rectParent.bottom = rectChild.bottom + help_fixup;
699 else
701 rectParent.bottom += rectChild.bottom;
704 /* finally use fixed parent size */
705 rectParent.bottom -= help_fixup;
707 /* set the size of the parent dialog */
708 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
709 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
710 SetWindowPos(hwndParentDlg, 0,
711 0, 0,
712 rectParent.right - rectParent.left,
713 rectParent.bottom - rectParent.top,
714 SWP_NOMOVE | SWP_NOZORDER);
717 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
719 switch(uMsg) {
720 case WM_INITDIALOG:
721 return TRUE;
723 return FALSE;
726 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
728 LPCVOID template;
729 HRSRC hRes;
730 HANDLE hDlgTmpl = 0;
731 HWND hChildDlg = 0;
733 TRACE("\n");
736 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
737 * structure's hInstance parameter is not a HINSTANCE, but
738 * instead a pointer to a template resource to use.
740 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
742 HINSTANCE hinst;
743 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
745 hinst = COMDLG32_hInstance;
746 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
748 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
749 return NULL;
752 else
754 hinst = fodInfos->ofnInfos->hInstance;
755 if(fodInfos->unicode)
757 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
758 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
760 else
762 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
763 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
765 if (!hRes)
767 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
768 return NULL;
770 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
771 !(template = LockResource( hDlgTmpl )))
773 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
774 return NULL;
777 if (fodInfos->unicode)
778 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
779 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
780 (LPARAM)fodInfos->ofnInfos);
781 else
782 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
783 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
784 (LPARAM)fodInfos->ofnInfos);
785 if(hChildDlg)
787 ShowWindow(hChildDlg,SW_SHOW);
788 return hChildDlg;
791 else if( IsHooked(fodInfos))
793 RECT rectHwnd;
794 struct {
795 DLGTEMPLATE tmplate;
796 WORD menu,class,title;
797 } temp;
798 GetClientRect(hwnd,&rectHwnd);
799 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
800 temp.tmplate.dwExtendedStyle = 0;
801 temp.tmplate.cdit = 0;
802 temp.tmplate.x = 0;
803 temp.tmplate.y = 0;
804 temp.tmplate.cx = 0;
805 temp.tmplate.cy = 0;
806 temp.menu = temp.class = temp.title = 0;
808 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
809 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
811 return hChildDlg;
813 return NULL;
816 /***********************************************************************
817 * SendCustomDlgNotificationMessage
819 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
822 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
824 LRESULT hook_result = 0;
826 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
828 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
830 if(!fodInfos) return 0;
832 if(fodInfos->DlgInfos.hwndCustomDlg)
834 TRACE("CALL NOTIFY for %x\n", uCode);
835 if(fodInfos->unicode)
837 OFNOTIFYW ofnNotify;
838 ofnNotify.hdr.hwndFrom=hwndParentDlg;
839 ofnNotify.hdr.idFrom=0;
840 ofnNotify.hdr.code = uCode;
841 ofnNotify.lpOFN = fodInfos->ofnInfos;
842 ofnNotify.pszFile = NULL;
843 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
845 else
847 OFNOTIFYA ofnNotify;
848 ofnNotify.hdr.hwndFrom=hwndParentDlg;
849 ofnNotify.hdr.idFrom=0;
850 ofnNotify.hdr.code = uCode;
851 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
852 ofnNotify.pszFile = NULL;
853 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
855 TRACE("RET NOTIFY\n");
857 TRACE("Retval: 0x%08lx\n", hook_result);
858 return hook_result;
861 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer)
863 UINT sizeUsed = 0, n, total;
864 LPWSTR lpstrFileList = NULL;
865 WCHAR lpstrCurrentDir[MAX_PATH];
866 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
868 TRACE("CDM_GETFILEPATH:\n");
870 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
871 return -1;
873 /* get path and filenames */
874 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrCurrentDir);
875 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
877 TRACE("path >%s< filespec >%s< %d files\n",
878 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
880 if( fodInfos->unicode )
882 LPWSTR bufW = buffer;
883 total = lstrlenW(lpstrCurrentDir) + 1 + sizeUsed;
885 /* Prepend the current path */
886 n = lstrlenW(lpstrCurrentDir) + 1;
887 memcpy( bufW, lpstrCurrentDir, min(n,size) * sizeof(WCHAR));
888 if(n<size)
890 /* 'n' includes trailing \0 */
891 bufW[n-1] = '\\';
892 memcpy( &bufW[n], lpstrFileList, (size-n)*sizeof(WCHAR) );
894 TRACE("returned -> %s\n",debugstr_wn(bufW, total));
896 else
898 LPSTR bufA = buffer;
899 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
900 NULL, 0, NULL, NULL);
901 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
902 NULL, 0, NULL, NULL);
904 /* Prepend the current path */
905 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
906 bufA, size, NULL, NULL);
908 if(n<size)
910 /* 'n' includes trailing \0 */
911 bufA[n-1] = '\\';
912 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
913 &bufA[n], size-n, NULL, NULL);
916 TRACE("returned -> %s\n",debugstr_an(bufA, total));
918 MemFree(lpstrFileList);
920 return total;
923 static INT_PTR FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer)
925 UINT sizeUsed = 0;
926 LPWSTR lpstrFileList = NULL;
927 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
929 TRACE("CDM_GETSPEC:\n");
931 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
932 if( fodInfos->unicode )
934 LPWSTR bufW = buffer;
935 memcpy( bufW, lpstrFileList, sizeof(WCHAR)*sizeUsed );
937 else
939 LPSTR bufA = buffer;
940 sizeUsed = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed,
941 NULL, 0, NULL, NULL);
942 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
943 bufA, size, NULL, NULL);
945 MemFree(lpstrFileList);
947 return sizeUsed;
950 /***********************************************************************
951 * FILEDLG95_HandleCustomDialogMessages
953 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
955 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
957 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
958 WCHAR lpstrPath[MAX_PATH];
959 INT_PTR retval;
961 if(!fodInfos) return FALSE;
963 switch(uMsg)
965 case CDM_GETFILEPATH:
966 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
967 break;
969 case CDM_GETFOLDERPATH:
970 TRACE("CDM_GETFOLDERPATH:\n");
971 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
972 if (lParam)
974 if (fodInfos->unicode)
975 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
976 else
977 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
978 (LPSTR)lParam, (int)wParam, NULL, NULL);
980 retval = lstrlenW(lpstrPath);
981 break;
983 case CDM_GETSPEC:
984 retval = FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
985 break;
987 case CDM_SETCONTROLTEXT:
988 TRACE("CDM_SETCONTROLTEXT:\n");
989 if ( lParam )
991 if( fodInfos->unicode )
992 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
993 else
994 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
996 retval = TRUE;
997 break;
999 case CDM_HIDECONTROL:
1000 /* MSDN states that it should fail for not OFN_EXPLORER case */
1001 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1003 HWND control = GetDlgItem( hwnd, wParam );
1004 if (control) ShowWindow( control, SW_HIDE );
1005 retval = TRUE;
1007 else retval = FALSE;
1008 break;
1010 default:
1011 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1012 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1013 return FALSE;
1015 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1016 return TRUE;
1019 /***********************************************************************
1020 * FileOpenDlgProc95
1022 * File open dialog procedure
1024 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1026 #if 0
1027 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
1028 #endif
1030 switch(uMsg)
1032 case WM_INITDIALOG:
1034 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1036 /* Adds the FileOpenDlgInfos in the property list of the dialog
1037 so it will be easily accessible through a GetPropA(...) */
1038 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
1040 fodInfos->DlgInfos.hwndCustomDlg =
1041 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1043 FILEDLG95_InitControls(hwnd);
1045 if (fodInfos->DlgInfos.hwndCustomDlg)
1047 RECT rc;
1048 UINT flags = SWP_NOACTIVATE;
1050 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1051 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1053 /* resize the custom dialog to the parent size */
1054 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1055 GetClientRect(hwnd, &rc);
1056 else
1058 /* our own fake template is zero sized and doesn't have
1059 * children, so there is no need to resize it.
1060 * Picasa depends on it.
1062 flags |= SWP_NOSIZE;
1063 SetRectEmpty(&rc);
1065 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1066 0, 0, rc.right, rc.bottom, flags);
1069 FILEDLG95_FillControls(hwnd, wParam, lParam);
1071 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1072 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1073 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1074 return 0;
1076 case WM_COMMAND:
1077 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1078 case WM_DRAWITEM:
1080 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1082 case IDC_LOOKIN:
1083 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1084 return TRUE;
1087 return FALSE;
1089 case WM_GETISHELLBROWSER:
1090 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1092 case WM_DESTROY:
1093 RemovePropA(hwnd, FileOpenDlgInfosStr);
1094 return FALSE;
1096 case WM_NOTIFY:
1098 LPNMHDR lpnmh = (LPNMHDR)lParam;
1099 UINT stringId = -1;
1101 /* set up the button tooltips strings */
1102 if(TTN_GETDISPINFOA == lpnmh->code )
1104 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1105 switch(lpnmh->idFrom )
1107 /* Up folder button */
1108 case FCIDM_TB_UPFOLDER:
1109 stringId = IDS_UPFOLDER;
1110 break;
1111 /* New folder button */
1112 case FCIDM_TB_NEWFOLDER:
1113 stringId = IDS_NEWFOLDER;
1114 break;
1115 /* List option button */
1116 case FCIDM_TB_SMALLICON:
1117 stringId = IDS_LISTVIEW;
1118 break;
1119 /* Details option button */
1120 case FCIDM_TB_REPORTVIEW:
1121 stringId = IDS_REPORTVIEW;
1122 break;
1123 /* Desktop button */
1124 case FCIDM_TB_DESKTOP:
1125 stringId = IDS_TODESKTOP;
1126 break;
1127 default:
1128 stringId = 0;
1130 lpdi->hinst = COMDLG32_hInstance;
1131 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1133 return FALSE;
1135 default :
1136 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1137 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1138 return FALSE;
1142 /***********************************************************************
1143 * FILEDLG95_InitControls
1145 * WM_INITDIALOG message handler (before hook notification)
1147 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1149 int win2000plus = 0;
1150 int win98plus = 0;
1151 int handledPath = FALSE;
1152 OSVERSIONINFOW osVi;
1153 static const WCHAR szwSlash[] = { '\\', 0 };
1154 static const WCHAR szwStar[] = { '*',0 };
1156 static const TBBUTTON tbb[] =
1158 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1159 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1160 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1161 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1162 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1163 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1164 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1165 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1166 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1168 TBADDBITMAP tba[2];
1169 RECT rectTB;
1170 RECT rectlook;
1171 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1173 tba[0].hInst = HINST_COMMCTRL;
1174 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1175 tba[1].hInst = COMDLG32_hInstance;
1176 tba[1].nID = 800;
1178 TRACE("%p\n", fodInfos);
1180 /* Get windows version emulating */
1181 osVi.dwOSVersionInfoSize = sizeof(osVi);
1182 GetVersionExW(&osVi);
1183 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1184 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1185 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1186 win2000plus = (osVi.dwMajorVersion > 4);
1187 if (win2000plus) win98plus = TRUE;
1189 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1191 /* Get the hwnd of the controls */
1192 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1193 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1194 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1196 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1197 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1199 /* construct the toolbar */
1200 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1201 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1203 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1204 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1205 rectTB.left = rectlook.right;
1206 rectTB.top = rectlook.top-1;
1208 if (fodInfos->unicode)
1209 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1210 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1211 rectTB.left, rectTB.top,
1212 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1213 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1214 else
1215 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1216 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1217 rectTB.left, rectTB.top,
1218 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1219 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1221 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1223 /* FIXME: use TB_LOADIMAGES when implemented */
1224 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1225 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba[0]);
1226 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 1, (LPARAM) &tba[1]);
1228 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) &tbb);
1229 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1231 /* Set the window text with the text specified in the OPENFILENAME structure */
1232 if(fodInfos->title)
1234 SetWindowTextW(hwnd,fodInfos->title);
1236 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1238 WCHAR buf[16];
1239 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1240 SetWindowTextW(hwnd, buf);
1243 /* Initialise the file name edit control */
1244 handledPath = FALSE;
1245 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1247 if(fodInfos->filename)
1249 /* 1. If win2000 or higher and filename contains a path, use it
1250 in preference over the lpstrInitialDir */
1251 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1252 WCHAR tmpBuf[MAX_PATH];
1253 WCHAR *nameBit;
1254 DWORD result;
1256 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1257 if (result) {
1259 /* nameBit is always shorter than the original filename */
1260 lstrcpyW(fodInfos->filename,nameBit);
1262 *nameBit = 0x00;
1263 if (fodInfos->initdir == NULL)
1264 MemFree(fodInfos->initdir);
1265 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1266 lstrcpyW(fodInfos->initdir, tmpBuf);
1267 handledPath = TRUE;
1268 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1269 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1271 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1273 } else {
1274 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1278 /* 2. (All platforms) If initdir is not null, then use it */
1279 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1280 (*fodInfos->initdir!=0x00))
1282 /* Work out the proper path as supplied one might be relative */
1283 /* (Here because supplying '.' as dir browses to My Computer) */
1284 if (handledPath==FALSE) {
1285 WCHAR tmpBuf[MAX_PATH];
1286 WCHAR tmpBuf2[MAX_PATH];
1287 WCHAR *nameBit;
1288 DWORD result;
1290 lstrcpyW(tmpBuf, fodInfos->initdir);
1291 if( PathFileExistsW(tmpBuf) ) {
1292 /* initdir does not have to be a directory. If a file is
1293 * specified, the dir part is taken */
1294 if( PathIsDirectoryW(tmpBuf)) {
1295 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1296 lstrcatW(tmpBuf, szwSlash);
1298 lstrcatW(tmpBuf, szwStar);
1300 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1301 if (result) {
1302 *nameBit = 0x00;
1303 MemFree(fodInfos->initdir);
1304 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1305 lstrcpyW(fodInfos->initdir, tmpBuf2);
1306 handledPath = TRUE;
1307 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1310 else if (fodInfos->initdir)
1312 MemFree(fodInfos->initdir);
1313 fodInfos->initdir = NULL;
1314 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1319 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1320 (*fodInfos->initdir==0x00)))
1322 /* 3. All except w2k+: if filename contains a path use it */
1323 if (!win2000plus && fodInfos->filename &&
1324 *fodInfos->filename &&
1325 strpbrkW(fodInfos->filename, szwSlash)) {
1326 WCHAR tmpBuf[MAX_PATH];
1327 WCHAR *nameBit;
1328 DWORD result;
1330 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1331 tmpBuf, &nameBit);
1332 if (result) {
1333 int len;
1335 /* nameBit is always shorter than the original filename */
1336 lstrcpyW(fodInfos->filename, nameBit);
1337 *nameBit = 0x00;
1339 len = lstrlenW(tmpBuf);
1340 MemFree(fodInfos->initdir);
1341 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1342 lstrcpyW(fodInfos->initdir, tmpBuf);
1344 handledPath = TRUE;
1345 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1346 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1348 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1351 /* 4. win98+ and win2000+ if any files of specified filter types in
1352 current directory, use it */
1353 if ( win98plus && handledPath == FALSE &&
1354 fodInfos->filter && *fodInfos->filter) {
1356 BOOL searchMore = TRUE;
1357 LPCWSTR lpstrPos = fodInfos->filter;
1358 WIN32_FIND_DATAW FindFileData;
1359 HANDLE hFind;
1361 while (searchMore)
1363 /* filter is a list... title\0ext\0......\0\0 */
1365 /* Skip the title */
1366 if(! *lpstrPos) break; /* end */
1367 lpstrPos += lstrlenW(lpstrPos) + 1;
1369 /* See if any files exist in the current dir with this extension */
1370 if(! *lpstrPos) break; /* end */
1372 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1374 if (hFind == INVALID_HANDLE_VALUE) {
1375 /* None found - continue search */
1376 lpstrPos += lstrlenW(lpstrPos) + 1;
1378 } else {
1379 searchMore = FALSE;
1381 MemFree(fodInfos->initdir);
1382 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1383 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1385 handledPath = TRUE;
1386 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1387 debugstr_w(lpstrPos));
1388 break;
1393 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1395 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1396 if (handledPath == FALSE && (win2000plus || win98plus)) {
1397 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1399 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1401 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1403 /* last fallback */
1404 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1405 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1406 } else {
1407 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1409 } else {
1410 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1412 handledPath = TRUE;
1413 } else if (handledPath==FALSE) {
1414 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1415 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1416 handledPath = TRUE;
1417 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1420 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1421 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1423 /* Must the open as read only check box be checked ?*/
1424 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1426 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1429 /* Must the open as read only check box be hidden? */
1430 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1432 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1433 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1436 /* Must the help button be hidden? */
1437 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1439 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1440 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1443 /* Resize the height, if open as read only checkbox ad help button
1444 are hidden and we are not using a custom template nor a customDialog
1446 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1447 (!(fodInfos->ofnInfos->Flags &
1448 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1449 (!fodInfos->DlgInfos.hwndCustomDlg ))
1451 RECT rectDlg, rectHelp, rectCancel;
1452 GetWindowRect(hwnd, &rectDlg);
1453 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1454 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1455 /* subtract the height of the help button plus the space between
1456 the help button and the cancel button to the height of the dialog */
1457 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1458 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1459 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1461 /* change Open to Save */
1462 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1464 WCHAR buf[16];
1465 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1466 SetDlgItemTextW(hwnd, IDOK, buf);
1467 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1468 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1470 return 0;
1473 /***********************************************************************
1474 * FILEDLG95_FillControls
1476 * WM_INITDIALOG message handler (after hook notification)
1478 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1480 LPITEMIDLIST pidlItemId = NULL;
1482 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1484 TRACE("dir=%s file=%s\n",
1485 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1487 /* Get the initial directory pidl */
1489 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1491 WCHAR path[MAX_PATH];
1493 GetCurrentDirectoryW(MAX_PATH,path);
1494 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1497 /* Initialise shell objects */
1498 FILEDLG95_SHELL_Init(hwnd);
1500 /* Initialize the Look In combo box */
1501 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1503 /* Initialize the filter combo box */
1504 FILEDLG95_FILETYPE_Init(hwnd);
1506 /* Browse to the initial directory */
1507 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1509 /* Free pidlItem memory */
1510 COMDLG32_SHFree(pidlItemId);
1512 return TRUE;
1514 /***********************************************************************
1515 * FILEDLG95_Clean
1517 * Regroups all the cleaning functions of the filedlg
1519 void FILEDLG95_Clean(HWND hwnd)
1521 FILEDLG95_FILETYPE_Clean(hwnd);
1522 FILEDLG95_LOOKIN_Clean(hwnd);
1523 FILEDLG95_SHELL_Clean(hwnd);
1525 /***********************************************************************
1526 * FILEDLG95_OnWMCommand
1528 * WM_COMMAND message handler
1530 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1532 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1533 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1534 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1536 switch(wID)
1538 /* OK button */
1539 case IDOK:
1540 FILEDLG95_OnOpen(hwnd);
1541 break;
1542 /* Cancel button */
1543 case IDCANCEL:
1544 FILEDLG95_Clean(hwnd);
1545 EndDialog(hwnd, FALSE);
1546 break;
1547 /* Filetype combo box */
1548 case IDC_FILETYPE:
1549 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1550 break;
1551 /* LookIn combo box */
1552 case IDC_LOOKIN:
1553 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1554 break;
1556 /* --- toolbar --- */
1557 /* Up folder button */
1558 case FCIDM_TB_UPFOLDER:
1559 FILEDLG95_SHELL_UpFolder(hwnd);
1560 break;
1561 /* New folder button */
1562 case FCIDM_TB_NEWFOLDER:
1563 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1564 break;
1565 /* List option button */
1566 case FCIDM_TB_SMALLICON:
1567 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1568 break;
1569 /* Details option button */
1570 case FCIDM_TB_REPORTVIEW:
1571 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1572 break;
1573 /* Details option button */
1574 case FCIDM_TB_DESKTOP:
1575 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1576 break;
1578 case IDC_FILENAME:
1579 break;
1582 /* Do not use the listview selection anymore */
1583 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1584 return 0;
1587 /***********************************************************************
1588 * FILEDLG95_OnWMGetIShellBrowser
1590 * WM_GETISHELLBROWSER message handler
1592 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1595 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1597 TRACE("\n");
1599 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1601 return TRUE;
1605 /***********************************************************************
1606 * FILEDLG95_SendFileOK
1608 * Sends the CDN_FILEOK notification if required
1610 * RETURNS
1611 * TRUE if the dialog should close
1612 * FALSE if the dialog should not be closed
1614 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1616 /* ask the hook if we can close */
1617 if(IsHooked(fodInfos))
1619 LRESULT retval;
1621 TRACE("---\n");
1622 /* First send CDN_FILEOK as MSDN doc says */
1623 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1624 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1626 TRACE("canceled\n");
1627 return (retval == 0);
1630 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1631 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1632 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1633 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1635 TRACE("canceled\n");
1636 return (retval == 0);
1639 return TRUE;
1642 /***********************************************************************
1643 * FILEDLG95_OnOpenMultipleFiles
1645 * Handles the opening of multiple files.
1647 * FIXME
1648 * check destination buffer size
1650 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1652 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1653 UINT nCount, nSizePath;
1654 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1656 TRACE("\n");
1658 if(fodInfos->unicode)
1660 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1661 ofn->lpstrFile[0] = '\0';
1663 else
1665 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1666 ofn->lpstrFile[0] = '\0';
1669 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1671 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1672 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1673 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1675 LPWSTR lpstrTemp = lpstrFileList;
1677 for ( nCount = 0; nCount < nFileCount; nCount++ )
1679 LPITEMIDLIST pidl;
1681 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1682 if (!pidl)
1684 WCHAR lpstrNotFound[100];
1685 WCHAR lpstrMsg[100];
1686 WCHAR tmp[400];
1687 static const WCHAR nl[] = {'\n',0};
1689 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1690 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1692 lstrcpyW(tmp, lpstrTemp);
1693 lstrcatW(tmp, nl);
1694 lstrcatW(tmp, lpstrNotFound);
1695 lstrcatW(tmp, nl);
1696 lstrcatW(tmp, lpstrMsg);
1698 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1699 return FALSE;
1702 /* move to the next file in the list of files */
1703 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1704 COMDLG32_SHFree(pidl);
1708 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1709 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1711 /* For "oldstyle" dialog the components have to
1712 be separated by blanks (not '\0'!) and short
1713 filenames have to be used! */
1714 FIXME("Components have to be separated by blanks\n");
1716 if(fodInfos->unicode)
1718 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1719 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1720 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1722 else
1724 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1726 if (ofn->lpstrFile != NULL)
1728 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1729 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1730 if (ofn->nMaxFile > nSizePath)
1732 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1733 ofn->lpstrFile + nSizePath,
1734 ofn->nMaxFile - nSizePath, NULL, NULL);
1739 fodInfos->ofnInfos->nFileOffset = nSizePath;
1740 fodInfos->ofnInfos->nFileExtension = 0;
1742 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1743 return FALSE;
1745 /* clean and exit */
1746 FILEDLG95_Clean(hwnd);
1747 return EndDialog(hwnd,TRUE);
1750 /***********************************************************************
1751 * FILEDLG95_OnOpen
1753 * Ok button WM_COMMAND message handler
1755 * If the function succeeds, the return value is nonzero.
1757 #define ONOPEN_BROWSE 1
1758 #define ONOPEN_OPEN 2
1759 #define ONOPEN_SEARCH 3
1760 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1762 WCHAR strMsgTitle[MAX_PATH];
1763 WCHAR strMsgText [MAX_PATH];
1764 if (idCaption)
1765 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1766 else
1767 strMsgTitle[0] = '\0';
1768 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1769 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1772 BOOL FILEDLG95_OnOpen(HWND hwnd)
1774 LPWSTR lpstrFileList;
1775 UINT nFileCount = 0;
1776 UINT sizeUsed = 0;
1777 BOOL ret = TRUE;
1778 WCHAR lpstrPathAndFile[MAX_PATH];
1779 WCHAR lpstrTemp[MAX_PATH];
1780 LPSHELLFOLDER lpsf = NULL;
1781 int nOpenAction;
1782 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1784 TRACE("hwnd=%p\n", hwnd);
1786 /* get the files from the edit control */
1787 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1789 /* try if the user selected a folder in the shellview */
1790 if(nFileCount == 0)
1792 BrowseSelectedFolder(hwnd);
1793 return FALSE;
1796 if(nFileCount > 1)
1798 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1799 goto ret;
1802 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1805 Step 1: Build a complete path name from the current folder and
1806 the filename or path in the edit box.
1807 Special cases:
1808 - the path in the edit box is a root path
1809 (with or without drive letter)
1810 - the edit box contains ".." (or a path with ".." in it)
1813 /* Get the current directory name */
1814 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1816 /* last fallback */
1817 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1819 PathAddBackslashW(lpstrPathAndFile);
1821 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1823 /* if the user specifyed a fully qualified path use it */
1824 if(PathIsRelativeW(lpstrFileList))
1826 lstrcatW(lpstrPathAndFile, lpstrFileList);
1828 else
1830 /* does the path have a drive letter? */
1831 if (PathGetDriveNumberW(lpstrFileList) == -1)
1832 lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
1833 else
1834 lstrcpyW(lpstrPathAndFile, lpstrFileList);
1837 /* resolve "." and ".." */
1838 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1839 lstrcpyW(lpstrPathAndFile, lpstrTemp);
1840 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1842 MemFree(lpstrFileList);
1845 Step 2: here we have a cleaned up path
1847 We have to parse the path step by step to see if we have to browse
1848 to a folder if the path points to a directory or the last
1849 valid element is a directory.
1851 valid variables:
1852 lpstrPathAndFile: cleaned up path
1855 if (nFileCount &&
1856 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1857 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1858 nOpenAction = ONOPEN_OPEN;
1859 else
1860 nOpenAction = ONOPEN_BROWSE;
1862 /* don't apply any checks with OFN_NOVALIDATE */
1864 LPWSTR lpszTemp, lpszTemp1;
1865 LPITEMIDLIST pidl = NULL;
1866 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1868 /* check for invalid chars */
1869 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1871 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1872 ret = FALSE;
1873 goto ret;
1876 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1878 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1879 while (lpszTemp1)
1881 LPSHELLFOLDER lpsfChild;
1882 WCHAR lpwstrTemp[MAX_PATH];
1883 DWORD dwEaten, dwAttributes;
1884 LPWSTR p;
1886 lstrcpyW(lpwstrTemp, lpszTemp);
1887 p = PathFindNextComponentW(lpwstrTemp);
1889 if (!p) break; /* end of path */
1891 *p = 0;
1892 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
1894 /* There are no wildcards when OFN_NOVALIDATE is set */
1895 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1897 static const WCHAR wszWild[] = { '*', '?', 0 };
1898 /* if the last element is a wildcard do a search */
1899 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1901 nOpenAction = ONOPEN_SEARCH;
1902 break;
1905 lpszTemp1 = lpszTemp;
1907 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1909 /* append a backslash to drive letters */
1910 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1911 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1912 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1914 PathAddBackslashW(lpwstrTemp);
1917 dwAttributes = SFGAO_FOLDER;
1918 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1920 /* the path component is valid, we have a pidl of the next path component */
1921 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
1922 if(dwAttributes & SFGAO_FOLDER)
1924 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1926 ERR("bind to failed\n"); /* should not fail */
1927 break;
1929 IShellFolder_Release(lpsf);
1930 lpsf = lpsfChild;
1931 lpsfChild = NULL;
1933 else
1935 TRACE("value\n");
1937 /* end dialog, return value */
1938 nOpenAction = ONOPEN_OPEN;
1939 break;
1941 COMDLG32_SHFree(pidl);
1942 pidl = NULL;
1944 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1946 if(*lpszTemp) /* points to trailing null for last path element */
1948 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1950 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1951 break;
1954 else
1956 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1957 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1959 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1960 break;
1963 /* change to the current folder */
1964 nOpenAction = ONOPEN_OPEN;
1965 break;
1967 else
1969 nOpenAction = ONOPEN_OPEN;
1970 break;
1973 if(pidl) COMDLG32_SHFree(pidl);
1977 Step 3: here we have a cleaned up and validated path
1979 valid variables:
1980 lpsf: ShellFolder bound to the rightmost valid path component
1981 lpstrPathAndFile: cleaned up path
1982 nOpenAction: action to do
1984 TRACE("end validate sf=%p\n", lpsf);
1986 switch(nOpenAction)
1988 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1989 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1991 int iPos;
1992 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1993 DWORD len;
1995 /* replace the current filter */
1996 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1997 len = lstrlenW(lpszTemp)+1;
1998 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1999 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2001 /* set the filter cb to the extension when possible */
2002 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2003 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2005 /* fall through */
2006 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2007 TRACE("ONOPEN_BROWSE\n");
2009 IPersistFolder2 * ppf2;
2010 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2012 LPITEMIDLIST pidlCurrent;
2013 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2014 IPersistFolder2_Release(ppf2);
2015 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2017 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE)))
2019 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2022 else if( nOpenAction == ONOPEN_SEARCH )
2024 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2026 COMDLG32_SHFree(pidlCurrent);
2027 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2030 ret = FALSE;
2031 break;
2032 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2033 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2035 WCHAR *ext = NULL;
2037 /* update READONLY check box flag */
2038 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2039 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2040 else
2041 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2043 /* Attach the file extension with file name*/
2044 ext = PathFindExtensionW(lpstrPathAndFile);
2045 if (! *ext)
2047 /* if no extension is specified with file name, then */
2048 /* attach the extension from file filter or default one */
2050 WCHAR *filterExt = NULL;
2051 LPWSTR lpstrFilter = NULL;
2052 static const WCHAR szwDot[] = {'.',0};
2053 int PathLength = lstrlenW(lpstrPathAndFile);
2055 /* Attach the dot*/
2056 lstrcatW(lpstrPathAndFile, szwDot);
2058 /*Get the file extension from file type filter*/
2059 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2060 fodInfos->ofnInfos->nFilterIndex-1);
2062 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2063 filterExt = PathFindExtensionW(lpstrFilter);
2065 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2066 lstrcatW(lpstrPathAndFile, filterExt + 1);
2067 else if ( fodInfos->defext ) /* attach the default file extension*/
2068 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2070 /* In Open dialog: if file does not exist try without extension */
2071 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2072 lpstrPathAndFile[PathLength] = '\0';
2075 if (fodInfos->defext) /* add default extension */
2077 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2078 if (*ext)
2079 ext++;
2080 if (!lstrcmpiW(fodInfos->defext, ext))
2081 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2082 else
2083 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2086 /* In Save dialog: check if the file already exists */
2087 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2088 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2089 && PathFileExistsW(lpstrPathAndFile))
2091 WCHAR lpstrOverwrite[100];
2092 int answer;
2094 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2095 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2096 MB_YESNO | MB_ICONEXCLAMATION);
2097 if (answer == IDNO)
2099 ret = FALSE;
2100 goto ret;
2104 /* Check that the size of the file does not exceed buffer size.
2105 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2106 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2107 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2109 LPWSTR lpszTemp;
2111 /* fill destination buffer */
2112 if (fodInfos->ofnInfos->lpstrFile)
2114 if(fodInfos->unicode)
2116 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2118 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2119 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2120 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2122 else
2124 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2126 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2127 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2128 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2129 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2133 /* set filename offset */
2134 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2135 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2137 /* set extension offset */
2138 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2139 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2141 /* set the lpstrFileTitle */
2142 if(fodInfos->ofnInfos->lpstrFileTitle)
2144 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2145 if(fodInfos->unicode)
2147 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2148 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2150 else
2152 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2153 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2154 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2158 /* copy currently selected filter to lpstrCustomFilter */
2159 if (fodInfos->ofnInfos->lpstrCustomFilter)
2161 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2162 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2163 NULL, 0, NULL, NULL);
2164 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2166 LPSTR s = ofn->lpstrCustomFilter;
2167 s += strlen(ofn->lpstrCustomFilter)+1;
2168 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2169 s, len, NULL, NULL);
2174 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2175 goto ret;
2177 TRACE("close\n");
2178 FILEDLG95_Clean(hwnd);
2179 ret = EndDialog(hwnd, TRUE);
2181 else
2183 WORD size;
2185 size = lstrlenW(lpstrPathAndFile) + 1;
2186 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2187 size += 1;
2188 /* return needed size in first two bytes of lpstrFile */
2189 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2190 FILEDLG95_Clean(hwnd);
2191 ret = EndDialog(hwnd, FALSE);
2192 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2194 goto ret;
2196 break;
2199 ret:
2200 if(lpsf) IShellFolder_Release(lpsf);
2201 return ret;
2204 /***********************************************************************
2205 * FILEDLG95_SHELL_Init
2207 * Initialisation of the shell objects
2209 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2211 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2213 TRACE("\n");
2216 * Initialisation of the FileOpenDialogInfos structure
2219 /* Shell */
2221 /*ShellInfos */
2222 fodInfos->ShellInfos.hwndOwner = hwnd;
2224 /* Disable multi-select if flag not set */
2225 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2227 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2229 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2230 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2232 /* Construct the IShellBrowser interface */
2233 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2235 return NOERROR;
2238 /***********************************************************************
2239 * FILEDLG95_SHELL_ExecuteCommand
2241 * Change the folder option and refresh the view
2242 * If the function succeeds, the return value is nonzero.
2244 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2246 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2248 IContextMenu * pcm;
2249 TRACE("(%p,%p)\n", hwnd, lpVerb);
2251 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2252 SVGIO_BACKGROUND,
2253 &IID_IContextMenu,
2254 (LPVOID*)&pcm)))
2256 CMINVOKECOMMANDINFO ci;
2257 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2258 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2259 ci.lpVerb = lpVerb;
2260 ci.hwnd = hwnd;
2262 IContextMenu_InvokeCommand(pcm, &ci);
2263 IContextMenu_Release(pcm);
2266 return FALSE;
2269 /***********************************************************************
2270 * FILEDLG95_SHELL_UpFolder
2272 * Browse to the specified object
2273 * If the function succeeds, the return value is nonzero.
2275 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2277 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2279 TRACE("\n");
2281 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2282 NULL,
2283 SBSP_PARENT)))
2285 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2286 return TRUE;
2288 return FALSE;
2291 /***********************************************************************
2292 * FILEDLG95_SHELL_BrowseToDesktop
2294 * Browse to the Desktop
2295 * If the function succeeds, the return value is nonzero.
2297 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2299 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2300 LPITEMIDLIST pidl;
2301 HRESULT hres;
2303 TRACE("\n");
2305 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2306 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2307 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2308 COMDLG32_SHFree(pidl);
2309 return SUCCEEDED(hres);
2311 /***********************************************************************
2312 * FILEDLG95_SHELL_Clean
2314 * Cleans the memory used by shell objects
2316 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2318 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2320 TRACE("\n");
2322 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2324 /* clean Shell interfaces */
2325 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2326 IShellView_Release(fodInfos->Shell.FOIShellView);
2327 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2328 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2329 if (fodInfos->Shell.FOIDataObject)
2330 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2333 /***********************************************************************
2334 * FILEDLG95_FILETYPE_Init
2336 * Initialisation of the file type combo box
2338 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2340 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2341 int nFilters = 0; /* number of filters */
2342 int nFilterIndexCB;
2344 TRACE("\n");
2346 if(fodInfos->customfilter)
2348 /* customfilter has one entry... title\0ext\0
2349 * Set first entry of combo box item with customfilter
2351 LPWSTR lpstrExt;
2352 LPCWSTR lpstrPos = fodInfos->customfilter;
2354 /* Get the title */
2355 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2357 /* Copy the extensions */
2358 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2359 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2360 lstrcpyW(lpstrExt,lpstrPos);
2362 /* Add the item at the end of the combo */
2363 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2364 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2365 nFilters++;
2367 if(fodInfos->filter)
2369 LPCWSTR lpstrPos = fodInfos->filter;
2371 for(;;)
2373 /* filter is a list... title\0ext\0......\0\0
2374 * Set the combo item text to the title and the item data
2375 * to the ext
2377 LPCWSTR lpstrDisplay;
2378 LPWSTR lpstrExt;
2380 /* Get the title */
2381 if(! *lpstrPos) break; /* end */
2382 lpstrDisplay = lpstrPos;
2383 lpstrPos += lstrlenW(lpstrPos) + 1;
2385 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2387 nFilters++;
2389 /* Copy the extensions */
2390 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2391 lstrcpyW(lpstrExt,lpstrPos);
2392 lpstrPos += lstrlenW(lpstrPos) + 1;
2394 /* Add the item at the end of the combo */
2395 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2397 /* malformed filters are added anyway... */
2398 if (!*lpstrExt) break;
2403 * Set the current filter to the one specified
2404 * in the initialisation structure
2406 if (fodInfos->filter || fodInfos->customfilter)
2408 LPWSTR lpstrFilter;
2410 /* Check to make sure our index isn't out of bounds. */
2411 if ( fodInfos->ofnInfos->nFilterIndex >
2412 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2413 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2415 /* set default filter index */
2416 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2417 fodInfos->ofnInfos->nFilterIndex = 1;
2419 /* calculate index of Combo Box item */
2420 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2421 if (fodInfos->customfilter == NULL)
2422 nFilterIndexCB--;
2424 /* Set the current index selection. */
2425 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2427 /* Get the corresponding text string from the combo box. */
2428 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2429 nFilterIndexCB);
2431 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2432 lpstrFilter = NULL;
2434 if(lpstrFilter)
2436 DWORD len;
2437 CharLowerW(lpstrFilter); /* lowercase */
2438 len = lstrlenW(lpstrFilter)+1;
2439 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2440 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2442 } else
2443 fodInfos->ofnInfos->nFilterIndex = 0;
2444 return S_OK;
2447 /***********************************************************************
2448 * FILEDLG95_FILETYPE_OnCommand
2450 * WM_COMMAND of the file type combo box
2451 * If the function succeeds, the return value is nonzero.
2453 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2455 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2457 switch(wNotifyCode)
2459 case CBN_SELENDOK:
2461 LPWSTR lpstrFilter;
2463 /* Get the current item of the filetype combo box */
2464 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2466 /* set the current filter index */
2467 fodInfos->ofnInfos->nFilterIndex = iItem +
2468 (fodInfos->customfilter == NULL ? 1 : 0);
2470 /* Set the current filter with the current selection */
2471 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2473 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2474 iItem);
2475 if((INT_PTR)lpstrFilter != CB_ERR)
2477 DWORD len;
2478 CharLowerW(lpstrFilter); /* lowercase */
2479 len = lstrlenW(lpstrFilter)+1;
2480 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2481 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2482 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2485 /* Refresh the actual view to display the included items*/
2486 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2489 return FALSE;
2491 /***********************************************************************
2492 * FILEDLG95_FILETYPE_SearchExt
2494 * searches for an extension in the filetype box
2496 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2498 int i, iCount = CBGetCount(hwnd);
2500 TRACE("%s\n", debugstr_w(lpstrExt));
2502 if(iCount != CB_ERR)
2504 for(i=0;i<iCount;i++)
2506 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2507 return i;
2510 return -1;
2513 /***********************************************************************
2514 * FILEDLG95_FILETYPE_Clean
2516 * Clean the memory used by the filetype combo box
2518 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2520 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2521 int iPos;
2522 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2524 TRACE("\n");
2526 /* Delete each string of the combo and their associated data */
2527 if(iCount != CB_ERR)
2529 for(iPos = iCount-1;iPos>=0;iPos--)
2531 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2532 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2535 /* Current filter */
2536 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2540 /***********************************************************************
2541 * FILEDLG95_LOOKIN_Init
2543 * Initialisation of the look in combo box
2546 /* Small helper function, to determine if the unixfs shell extension is rooted
2547 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2549 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2550 HKEY hKey;
2551 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2552 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2553 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2554 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2555 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2556 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2557 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2559 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2560 return FALSE;
2562 RegCloseKey(hKey);
2563 return TRUE;
2566 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2568 IShellFolder *psfRoot, *psfDrives;
2569 IEnumIDList *lpeRoot, *lpeDrives;
2570 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2572 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2574 TRACE("\n");
2576 liInfos->iMaxIndentation = 0;
2578 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2580 /* set item height for both text field and listbox */
2581 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2582 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2584 /* Turn on the extended UI for the combo box like Windows does */
2585 CBSetExtendedUI(hwndCombo, TRUE);
2587 /* Initialise data of Desktop folder */
2588 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2589 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2590 COMDLG32_SHFree(pidlTmp);
2592 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2594 SHGetDesktopFolder(&psfRoot);
2596 if (psfRoot)
2598 /* enumerate the contents of the desktop */
2599 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2601 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2603 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2605 /* If the unixfs extension is rooted, we don't expand the drives by default */
2606 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2608 /* special handling for CSIDL_DRIVES */
2609 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2611 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2613 /* enumerate the drives */
2614 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2616 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2618 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2619 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2620 COMDLG32_SHFree(pidlAbsTmp);
2621 COMDLG32_SHFree(pidlTmp1);
2623 IEnumIDList_Release(lpeDrives);
2625 IShellFolder_Release(psfDrives);
2630 COMDLG32_SHFree(pidlTmp);
2632 IEnumIDList_Release(lpeRoot);
2634 IShellFolder_Release(psfRoot);
2637 COMDLG32_SHFree(pidlDrives);
2640 /***********************************************************************
2641 * FILEDLG95_LOOKIN_DrawItem
2643 * WM_DRAWITEM message handler
2645 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2647 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2648 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2649 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2650 RECT rectText;
2651 RECT rectIcon;
2652 SHFILEINFOW sfi;
2653 HIMAGELIST ilItemImage;
2654 int iIndentation;
2655 TEXTMETRICW tm;
2656 LPSFOLDER tmpFolder;
2659 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2661 TRACE("\n");
2663 if(pDIStruct->itemID == -1)
2664 return 0;
2666 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2667 pDIStruct->itemID)))
2668 return 0;
2671 if(pDIStruct->itemID == liInfos->uSelectedItem)
2673 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2675 &sfi,
2676 sizeof (sfi),
2677 SHGFI_PIDL | SHGFI_SMALLICON |
2678 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2679 SHGFI_DISPLAYNAME );
2681 else
2683 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2685 &sfi,
2686 sizeof (sfi),
2687 SHGFI_PIDL | SHGFI_SMALLICON |
2688 SHGFI_SYSICONINDEX |
2689 SHGFI_DISPLAYNAME);
2692 /* Is this item selected ? */
2693 if(pDIStruct->itemState & ODS_SELECTED)
2695 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2696 SetBkColor(pDIStruct->hDC,crHighLight);
2697 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2699 else
2701 SetTextColor(pDIStruct->hDC,crText);
2702 SetBkColor(pDIStruct->hDC,crWin);
2703 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2706 /* Do not indent item if drawing in the edit of the combo */
2707 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2709 iIndentation = 0;
2710 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2712 &sfi,
2713 sizeof (sfi),
2714 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2715 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2718 else
2720 iIndentation = tmpFolder->m_iIndent;
2722 /* Draw text and icon */
2724 /* Initialise the icon display area */
2725 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2726 rectIcon.top = pDIStruct->rcItem.top;
2727 rectIcon.right = rectIcon.left + ICONWIDTH;
2728 rectIcon.bottom = pDIStruct->rcItem.bottom;
2730 /* Initialise the text display area */
2731 GetTextMetricsW(pDIStruct->hDC, &tm);
2732 rectText.left = rectIcon.right;
2733 rectText.top =
2734 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2735 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2736 rectText.bottom =
2737 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2739 /* Draw the icon from the image list */
2740 ImageList_Draw(ilItemImage,
2741 sfi.iIcon,
2742 pDIStruct->hDC,
2743 rectIcon.left,
2744 rectIcon.top,
2745 ILD_TRANSPARENT );
2747 /* Draw the associated text */
2748 if(sfi.szDisplayName)
2749 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
2752 return NOERROR;
2755 /***********************************************************************
2756 * FILEDLG95_LOOKIN_OnCommand
2758 * LookIn combo box WM_COMMAND message handler
2759 * If the function succeeds, the return value is nonzero.
2761 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2763 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2765 TRACE("%p\n", fodInfos);
2767 switch(wNotifyCode)
2769 case CBN_SELENDOK:
2771 LPSFOLDER tmpFolder;
2772 int iItem;
2774 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2776 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2777 iItem)))
2778 return FALSE;
2781 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2782 tmpFolder->pidlItem,
2783 SBSP_ABSOLUTE)))
2785 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2786 return TRUE;
2788 break;
2792 return FALSE;
2795 /***********************************************************************
2796 * FILEDLG95_LOOKIN_AddItem
2798 * Adds an absolute pidl item to the lookin combo box
2799 * returns the index of the inserted item
2801 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2803 LPITEMIDLIST pidlNext;
2804 SHFILEINFOW sfi;
2805 SFOLDER *tmpFolder;
2806 LookInInfos *liInfos;
2808 TRACE("%08x\n", iInsertId);
2810 if(!pidl)
2811 return -1;
2813 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2814 return -1;
2816 tmpFolder = MemAlloc(sizeof(SFOLDER));
2817 tmpFolder->m_iIndent = 0;
2819 /* Calculate the indentation of the item in the lookin*/
2820 pidlNext = pidl;
2821 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2823 tmpFolder->m_iIndent++;
2826 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2828 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2829 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2831 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2832 SHGetFileInfoW((LPCWSTR)pidl,
2834 &sfi,
2835 sizeof(sfi),
2836 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2837 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2839 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
2841 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2843 int iItemID;
2845 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
2847 /* Add the item at the end of the list */
2848 if(iInsertId < 0)
2850 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2852 /* Insert the item at the iInsertId position*/
2853 else
2855 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2858 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2859 return iItemID;
2862 COMDLG32_SHFree( tmpFolder->pidlItem );
2863 MemFree( tmpFolder );
2864 return -1;
2868 /***********************************************************************
2869 * FILEDLG95_LOOKIN_InsertItemAfterParent
2871 * Insert an item below its parent
2873 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2876 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2877 int iParentPos;
2879 TRACE("\n");
2881 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2883 if(iParentPos < 0)
2885 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2888 /* Free pidlParent memory */
2889 COMDLG32_SHFree((LPVOID)pidlParent);
2891 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2894 /***********************************************************************
2895 * FILEDLG95_LOOKIN_SelectItem
2897 * Adds an absolute pidl item to the lookin combo box
2898 * returns the index of the inserted item
2900 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2902 int iItemPos;
2903 LookInInfos *liInfos;
2905 TRACE("\n");
2907 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2909 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2911 if(iItemPos < 0)
2913 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2914 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2917 else
2919 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2920 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2922 int iRemovedItem;
2924 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2925 break;
2926 if(iRemovedItem < iItemPos)
2927 iItemPos--;
2931 CBSetCurSel(hwnd,iItemPos);
2932 liInfos->uSelectedItem = iItemPos;
2934 return 0;
2938 /***********************************************************************
2939 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2941 * Remove the item with an expansion level over iExpansionLevel
2943 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2945 int iItemPos;
2947 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2949 TRACE("\n");
2951 if(liInfos->iMaxIndentation <= 2)
2952 return -1;
2954 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2956 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2957 COMDLG32_SHFree(tmpFolder->pidlItem);
2958 MemFree(tmpFolder);
2959 CBDeleteString(hwnd,iItemPos);
2960 liInfos->iMaxIndentation--;
2962 return iItemPos;
2965 return -1;
2968 /***********************************************************************
2969 * FILEDLG95_LOOKIN_SearchItem
2971 * Search for pidl in the lookin combo box
2972 * returns the index of the found item
2974 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2976 int i = 0;
2977 int iCount = CBGetCount(hwnd);
2979 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2981 if (iCount != CB_ERR)
2983 for(;i<iCount;i++)
2985 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2987 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2988 return i;
2989 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2990 return i;
2994 return -1;
2997 /***********************************************************************
2998 * FILEDLG95_LOOKIN_Clean
3000 * Clean the memory used by the lookin combo box
3002 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3004 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3005 int iPos;
3006 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3008 TRACE("\n");
3010 /* Delete each string of the combo and their associated data */
3011 if (iCount != CB_ERR)
3013 for(iPos = iCount-1;iPos>=0;iPos--)
3015 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3016 COMDLG32_SHFree(tmpFolder->pidlItem);
3017 MemFree(tmpFolder);
3018 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3022 /* LookInInfos structure */
3023 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3026 /***********************************************************************
3027 * FILEDLG95_FILENAME_FillFromSelection
3029 * fills the edit box from the cached DataObject
3031 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3033 FileOpenDlgInfos *fodInfos;
3034 LPITEMIDLIST pidl;
3035 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3036 WCHAR lpstrTemp[MAX_PATH];
3037 LPWSTR lpstrAllFile, lpstrCurrFile;
3039 TRACE("\n");
3040 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3042 /* Count how many files we have */
3043 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3045 /* calculate the string length, count files */
3046 if (nFileSelected >= 1)
3048 nLength += 3; /* first and last quotes, trailing \0 */
3049 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3051 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3053 if (pidl)
3055 /* get the total length of the selected file names */
3056 lpstrTemp[0] = '\0';
3057 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3059 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3061 nLength += lstrlenW( lpstrTemp ) + 3;
3062 nFiles++;
3064 COMDLG32_SHFree( pidl );
3069 /* allocate the buffer */
3070 if (nFiles <= 1) nLength = MAX_PATH;
3071 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3073 /* Generate the string for the edit control */
3074 if(nFiles >= 1)
3076 lpstrCurrFile = lpstrAllFile;
3077 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3079 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3081 if (pidl)
3083 /* get the file name */
3084 lpstrTemp[0] = '\0';
3085 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3087 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3089 if ( nFiles > 1)
3091 *lpstrCurrFile++ = '\"';
3092 lstrcpyW( lpstrCurrFile, lpstrTemp );
3093 lpstrCurrFile += lstrlenW( lpstrTemp );
3094 *lpstrCurrFile++ = '\"';
3095 *lpstrCurrFile++ = ' ';
3096 *lpstrCurrFile = 0;
3098 else
3100 lstrcpyW( lpstrAllFile, lpstrTemp );
3103 COMDLG32_SHFree( (LPVOID) pidl );
3106 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3108 /* Select the file name like Windows does */
3109 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3111 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3115 /* copied from shell32 to avoid linking to it
3116 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3117 * is dependent on whether emulated OS is unicode or not.
3119 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3121 switch (src->uType)
3123 case STRRET_WSTR:
3124 lstrcpynW(dest, src->u.pOleStr, len);
3125 COMDLG32_SHFree(src->u.pOleStr);
3126 break;
3128 case STRRET_CSTR:
3129 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3130 dest[len-1] = 0;
3131 break;
3133 case STRRET_OFFSET:
3134 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3135 dest[len-1] = 0;
3136 break;
3138 default:
3139 FIXME("unknown type %x!\n", src->uType);
3140 if (len) *dest = '\0';
3141 return E_FAIL;
3143 return S_OK;
3146 /***********************************************************************
3147 * FILEDLG95_FILENAME_GetFileNames
3149 * Copies the filenames to a delimited string list.
3150 * The delimiter is specified by the parameter 'separator',
3151 * usually either a space or a nul
3153 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3155 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3156 UINT nStrCharCount = 0; /* index in src buffer */
3157 UINT nFileIndex = 0; /* index in dest buffer */
3158 UINT nFileCount = 0; /* number of files */
3159 UINT nStrLen = 0; /* length of string in edit control */
3160 LPWSTR lpstrEdit; /* buffer for string from edit control */
3162 TRACE("\n");
3164 /* get the filenames from the edit control */
3165 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3166 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3167 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3169 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3171 /* we might get single filename without any '"',
3172 * so we need nStrLen + terminating \0 + end-of-list \0 */
3173 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3174 *sizeUsed = 0;
3176 /* build delimited file list from filenames */
3177 while ( nStrCharCount <= nStrLen )
3179 if ( lpstrEdit[nStrCharCount]=='"' )
3181 nStrCharCount++;
3182 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3184 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3185 (*sizeUsed)++;
3186 nStrCharCount++;
3188 (*lpstrFileList)[nFileIndex++] = separator;
3189 (*sizeUsed)++;
3190 nFileCount++;
3192 nStrCharCount++;
3195 /* single, unquoted string */
3196 if ((nStrLen > 0) && (*sizeUsed == 0) )
3198 lstrcpyW(*lpstrFileList, lpstrEdit);
3199 nFileIndex = lstrlenW(lpstrEdit) + 1;
3200 (*sizeUsed) = nFileIndex;
3201 nFileCount = 1;
3204 /* trailing \0 */
3205 (*lpstrFileList)[nFileIndex] = '\0';
3206 (*sizeUsed)++;
3208 MemFree(lpstrEdit);
3209 return nFileCount;
3212 #define SETDefFormatEtc(fe,cf,med) \
3214 (fe).cfFormat = cf;\
3215 (fe).dwAspect = DVASPECT_CONTENT; \
3216 (fe).ptd =NULL;\
3217 (fe).tymed = med;\
3218 (fe).lindex = -1;\
3222 * DATAOBJECT Helper functions
3225 /***********************************************************************
3226 * COMCTL32_ReleaseStgMedium
3228 * like ReleaseStgMedium from ole32
3230 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3232 if(medium.pUnkForRelease)
3234 IUnknown_Release(medium.pUnkForRelease);
3236 else
3238 GlobalUnlock(medium.u.hGlobal);
3239 GlobalFree(medium.u.hGlobal);
3243 /***********************************************************************
3244 * GetPidlFromDataObject
3246 * Return pidl(s) by number from the cached DataObject
3248 * nPidlIndex=0 gets the fully qualified root path
3250 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3253 STGMEDIUM medium;
3254 FORMATETC formatetc;
3255 LPITEMIDLIST pidl = NULL;
3257 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3259 if (!doSelected)
3260 return NULL;
3262 /* Set the FORMATETC structure*/
3263 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3265 /* Get the pidls from IDataObject */
3266 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3268 LPIDA cida = GlobalLock(medium.u.hGlobal);
3269 if(nPidlIndex <= cida->cidl)
3271 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3273 COMCTL32_ReleaseStgMedium(medium);
3275 return pidl;
3278 /***********************************************************************
3279 * GetNumSelected
3281 * Return the number of selected items in the DataObject.
3284 UINT GetNumSelected( IDataObject *doSelected )
3286 UINT retVal = 0;
3287 STGMEDIUM medium;
3288 FORMATETC formatetc;
3290 TRACE("sv=%p\n", doSelected);
3292 if (!doSelected) return 0;
3294 /* Set the FORMATETC structure*/
3295 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3297 /* Get the pidls from IDataObject */
3298 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3300 LPIDA cida = GlobalLock(medium.u.hGlobal);
3301 retVal = cida->cidl;
3302 COMCTL32_ReleaseStgMedium(medium);
3303 return retVal;
3305 return 0;
3309 * TOOLS
3312 /***********************************************************************
3313 * GetName
3315 * Get the pidl's display name (relative to folder) and
3316 * put it in lpstrFileName.
3318 * Return NOERROR on success,
3319 * E_FAIL otherwise
3322 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3324 STRRET str;
3325 HRESULT hRes;
3327 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3329 if(!lpsf)
3331 SHGetDesktopFolder(&lpsf);
3332 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3333 IShellFolder_Release(lpsf);
3334 return hRes;
3337 /* Get the display name of the pidl relative to the folder */
3338 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3340 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3342 return E_FAIL;
3345 /***********************************************************************
3346 * GetShellFolderFromPidl
3348 * pidlRel is the item pidl relative
3349 * Return the IShellFolder of the absolute pidl
3351 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3353 IShellFolder *psf = NULL,*psfParent;
3355 TRACE("%p\n", pidlAbs);
3357 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3359 psf = psfParent;
3360 if(pidlAbs && pidlAbs->mkid.cb)
3362 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3364 IShellFolder_Release(psfParent);
3365 return psf;
3368 /* return the desktop */
3369 return psfParent;
3371 return NULL;
3374 /***********************************************************************
3375 * GetParentPidl
3377 * Return the LPITEMIDLIST to the parent of the pidl in the list
3379 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3381 LPITEMIDLIST pidlParent;
3383 TRACE("%p\n", pidl);
3385 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3386 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3388 return pidlParent;
3391 /***********************************************************************
3392 * GetPidlFromName
3394 * returns the pidl of the file name relative to folder
3395 * NULL if an error occurred
3397 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3399 LPITEMIDLIST pidl = NULL;
3400 ULONG ulEaten;
3402 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3404 if(!lpcstrFileName) return NULL;
3405 if(!*lpcstrFileName) return NULL;
3407 if(!lpsf)
3409 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3410 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3411 IShellFolder_Release(lpsf);
3414 else
3416 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3418 return pidl;
3423 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3425 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3426 HRESULT ret;
3428 TRACE("%p, %p\n", psf, pidl);
3430 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3432 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3433 /* see documentation shell 4.1*/
3434 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3437 /***********************************************************************
3438 * BrowseSelectedFolder
3440 static BOOL BrowseSelectedFolder(HWND hwnd)
3442 BOOL bBrowseSelFolder = FALSE;
3443 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3445 TRACE("\n");
3447 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3449 LPITEMIDLIST pidlSelection;
3451 /* get the file selected */
3452 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3453 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3455 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3456 pidlSelection, SBSP_RELATIVE ) ) )
3458 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3459 ' ','n','o','t',' ','e','x','i','s','t',0};
3460 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3462 bBrowseSelFolder = TRUE;
3463 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3465 COMDLG32_SHFree( pidlSelection );
3468 return bBrowseSelFolder;
3472 * Memory allocation methods */
3473 static void *MemAlloc(UINT size)
3475 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3478 static void MemFree(void *mem)
3480 HeapFree(GetProcessHeap(),0,mem);
3484 * Old-style (win3.1) dialogs */
3486 /***********************************************************************
3487 * FD32_GetTemplate [internal]
3489 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3490 * by a 32 bits application
3493 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3495 LPOPENFILENAMEW ofnW = lfs->ofnW;
3496 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3497 HANDLE hDlgTmpl;
3499 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3501 if (!(lfs->template = LockResource( ofnW->hInstance )))
3503 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3504 return FALSE;
3507 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3509 HRSRC hResInfo;
3510 if (priv->ofnA)
3511 hResInfo = FindResourceA(priv->ofnA->hInstance,
3512 priv->ofnA->lpTemplateName,
3513 (LPSTR)RT_DIALOG);
3514 else
3515 hResInfo = FindResourceW(ofnW->hInstance,
3516 ofnW->lpTemplateName,
3517 (LPWSTR)RT_DIALOG);
3518 if (!hResInfo)
3520 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3521 return FALSE;
3523 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3524 hResInfo)) ||
3525 !(lfs->template = LockResource(hDlgTmpl)))
3527 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3528 return FALSE;
3530 } else { /* get it from internal Wine resource */
3531 HRSRC hResInfo;
3532 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3533 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3535 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3536 return FALSE;
3538 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3539 !(lfs->template = LockResource( hDlgTmpl )))
3541 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3542 return FALSE;
3545 return TRUE;
3549 /************************************************************************
3550 * FD32_Init [internal]
3551 * called from the common 16/32 code to initialize 32 bit data
3553 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3555 BOOL IsUnicode = (BOOL) data;
3556 PFD32_PRIVATE priv;
3558 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3559 lfs->private1632 = priv;
3560 if (NULL == lfs->private1632) return FALSE;
3561 if (IsUnicode)
3563 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3564 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3565 if (lfs->ofnW->lpfnHook)
3566 lfs->hook = TRUE;
3568 else
3570 priv->ofnA = (LPOPENFILENAMEA) lParam;
3571 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3572 if (priv->ofnA->lpfnHook)
3573 lfs->hook = TRUE;
3574 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3575 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3578 if (! FD32_GetTemplate(lfs)) return FALSE;
3580 return TRUE;
3583 /***********************************************************************
3584 * FD32_CallWindowProc [internal]
3586 * called from the common 16/32 code to call the appropriate hook
3588 static BOOL CALLBACK FD32_CallWindowProc(const FD31_DATA *lfs, UINT wMsg, WPARAM wParam,
3589 LPARAM lParam)
3591 BOOL ret;
3592 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3594 if (priv->ofnA)
3596 TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3597 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3598 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3599 TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3600 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3601 return ret;
3604 TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3605 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3606 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3607 TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3608 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3609 return ret;
3612 /***********************************************************************
3613 * FD32_UpdateResult [internal]
3614 * update the real client structures if any
3616 static void CALLBACK FD32_UpdateResult(const FD31_DATA *lfs)
3618 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3619 LPOPENFILENAMEW ofnW = lfs->ofnW;
3621 if (priv->ofnA)
3623 if (ofnW->nMaxFile &&
3624 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3625 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3626 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3627 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3628 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3632 /***********************************************************************
3633 * FD32_UpdateFileTitle [internal]
3634 * update the real client structures if any
3636 static void CALLBACK FD32_UpdateFileTitle(const FD31_DATA *lfs)
3638 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3639 LPOPENFILENAMEW ofnW = lfs->ofnW;
3641 if (priv->ofnA)
3643 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3644 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3645 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3650 /***********************************************************************
3651 * FD32_SendLbGetCurSel [internal]
3652 * retrieve selected listbox item
3654 static LRESULT CALLBACK FD32_SendLbGetCurSel(const FD31_DATA *lfs)
3656 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3660 /************************************************************************
3661 * FD32_Destroy [internal]
3662 * called from the common 16/32 code to cleanup 32 bit data
3664 static void CALLBACK FD32_Destroy(const FD31_DATA *lfs)
3666 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3668 /* if ofnW has been allocated, have to free everything in it */
3669 if (NULL != priv && NULL != priv->ofnA)
3671 FD31_FreeOfnW(lfs->ofnW);
3672 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3676 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3678 callbacks->Init = FD32_Init;
3679 callbacks->CWP = FD32_CallWindowProc;
3680 callbacks->UpdateResult = FD32_UpdateResult;
3681 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3682 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3683 callbacks->Destroy = FD32_Destroy;
3686 /***********************************************************************
3687 * FD32_WMMeasureItem [internal]
3689 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3691 LPMEASUREITEMSTRUCT lpmeasure;
3693 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3694 lpmeasure->itemHeight = FD31_GetFldrHeight();
3695 return TRUE;
3699 /***********************************************************************
3700 * FileOpenDlgProc [internal]
3701 * Used for open and save, in fact.
3703 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3704 WPARAM wParam, LPARAM lParam)
3706 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3708 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
3709 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3711 INT_PTR lRet;
3712 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3713 if (lRet)
3714 return lRet; /* else continue message processing */
3716 switch (wMsg)
3718 case WM_INITDIALOG:
3719 return FD31_WMInitDialog(hWnd, wParam, lParam);
3721 case WM_MEASUREITEM:
3722 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3724 case WM_DRAWITEM:
3725 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3727 case WM_COMMAND:
3728 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3729 #if 0
3730 case WM_CTLCOLOR:
3731 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3732 switch (HIWORD(lParam))
3734 case CTLCOLOR_BTN:
3735 SetTextColor((HDC16)wParam, 0x00000000);
3736 return hGRAYBrush;
3737 case CTLCOLOR_STATIC:
3738 SetTextColor((HDC16)wParam, 0x00000000);
3739 return hGRAYBrush;
3741 break;
3742 #endif
3744 return FALSE;
3748 /***********************************************************************
3749 * GetFileName31A [internal]
3751 * Creates a win31 style dialog box for the user to select a file to open/save.
3753 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3754 UINT dlgType /* type dialogue : open/save */
3757 HINSTANCE hInst;
3758 BOOL bRet = FALSE;
3759 PFD31_DATA lfs;
3760 FD31_CALLBACKS callbacks;
3762 if (!lpofn || !FD31_Init()) return FALSE;
3764 TRACE("ofn flags %08x\n", lpofn->Flags);
3765 FD32_SetupCallbacks(&callbacks);
3766 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3767 if (lfs)
3769 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3770 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3771 FD32_FileOpenDlgProc, (LPARAM)lfs);
3772 FD31_DestroyPrivate(lfs);
3775 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3776 return bRet;
3779 /***********************************************************************
3780 * GetFileName31W [internal]
3782 * Creates a win31 style dialog box for the user to select a file to open/save
3784 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3785 UINT dlgType /* type dialogue : open/save */
3788 HINSTANCE hInst;
3789 BOOL bRet = FALSE;
3790 PFD31_DATA lfs;
3791 FD31_CALLBACKS callbacks;
3793 if (!lpofn || !FD31_Init()) return FALSE;
3795 FD32_SetupCallbacks(&callbacks);
3796 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3797 if (lfs)
3799 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3800 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3801 FD32_FileOpenDlgProc, (LPARAM)lfs);
3802 FD31_DestroyPrivate(lfs);
3805 TRACE("file %s, file offset %d, ext offset %d\n",
3806 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3807 return bRet;
3810 /* ------------------ APIs ---------------------- */
3812 /***********************************************************************
3813 * GetOpenFileNameA (COMDLG32.@)
3815 * Creates a dialog box for the user to select a file to open.
3817 * RETURNS
3818 * TRUE on success: user enters a valid file
3819 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3822 BOOL WINAPI GetOpenFileNameA(
3823 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3825 BOOL win16look = FALSE;
3827 TRACE("flags %08x\n", ofn->Flags);
3829 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3830 if (ofn->Flags & OFN_FILEMUSTEXIST)
3831 ofn->Flags |= OFN_PATHMUSTEXIST;
3833 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3834 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3836 if (win16look)
3837 return GetFileName31A(ofn, OPEN_DIALOG);
3838 else
3839 return GetFileDialog95A(ofn, OPEN_DIALOG);
3842 /***********************************************************************
3843 * GetOpenFileNameW (COMDLG32.@)
3845 * Creates a dialog box for the user to select a file to open.
3847 * RETURNS
3848 * TRUE on success: user enters a valid file
3849 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3852 BOOL WINAPI GetOpenFileNameW(
3853 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3855 BOOL win16look = FALSE;
3857 TRACE("flags %08x\n", ofn->Flags);
3859 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3860 if (ofn->Flags & OFN_FILEMUSTEXIST)
3861 ofn->Flags |= OFN_PATHMUSTEXIST;
3863 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3864 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3866 if (win16look)
3867 return GetFileName31W(ofn, OPEN_DIALOG);
3868 else
3869 return GetFileDialog95W(ofn, OPEN_DIALOG);
3873 /***********************************************************************
3874 * GetSaveFileNameA (COMDLG32.@)
3876 * Creates a dialog box for the user to select a file to save.
3878 * RETURNS
3879 * TRUE on success: user enters a valid file
3880 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3883 BOOL WINAPI GetSaveFileNameA(
3884 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3886 BOOL win16look = FALSE;
3888 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3889 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3891 if (win16look)
3892 return GetFileName31A(ofn, SAVE_DIALOG);
3893 else
3894 return GetFileDialog95A(ofn, SAVE_DIALOG);
3897 /***********************************************************************
3898 * GetSaveFileNameW (COMDLG32.@)
3900 * Creates a dialog box for the user to select a file to save.
3902 * RETURNS
3903 * TRUE on success: user enters a valid file
3904 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3907 BOOL WINAPI GetSaveFileNameW(
3908 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3910 BOOL win16look = FALSE;
3912 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3913 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3915 if (win16look)
3916 return GetFileName31W(ofn, SAVE_DIALOG);
3917 else
3918 return GetFileDialog95W(ofn, SAVE_DIALOG);
3921 /***********************************************************************
3922 * GetFileTitleA (COMDLG32.@)
3924 * See GetFileTitleW.
3926 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
3928 int ret;
3929 UNICODE_STRING strWFile;
3930 LPWSTR lpWTitle;
3932 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
3933 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
3934 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
3935 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
3936 RtlFreeUnicodeString( &strWFile );
3937 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
3938 return ret;
3942 /***********************************************************************
3943 * GetFileTitleW (COMDLG32.@)
3945 * Get the name of a file.
3947 * PARAMS
3948 * lpFile [I] name and location of file
3949 * lpTitle [O] returned file name
3950 * cbBuf [I] buffer size of lpTitle
3952 * RETURNS
3953 * Success: zero
3954 * Failure: negative number.
3956 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
3958 int i, len;
3959 static const WCHAR brkpoint[] = {'*','[',']',0};
3960 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
3962 if(lpFile == NULL || lpTitle == NULL)
3963 return -1;
3965 len = lstrlenW(lpFile);
3967 if (len == 0)
3968 return -1;
3970 if(strpbrkW(lpFile, brkpoint))
3971 return -1;
3973 len--;
3975 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
3976 return -1;
3978 for(i = len; i >= 0; i--)
3980 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
3982 i++;
3983 break;
3987 if(i == -1)
3988 i++;
3990 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
3992 len = lstrlenW(lpFile+i)+1;
3993 if(cbBuf < len)
3994 return len;
3996 lstrcpyW(lpTitle, &lpFile[i]);
3997 return 0;