wrc: Clean output files when aborting on an error or signal.
[wine/multimedia.git] / dlls / comdlg32 / filedlg.c
blob68c2fef310790e6429cc03b3cfdb659531f7f88a
1 /*
2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_CREATEPROMPT, OFN_DONTADDTORECENT,
40 * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING,
41 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
42 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
44 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
49 #include "config.h"
50 #include "wine/port.h"
52 #include <ctype.h>
53 #include <stdlib.h>
54 #include <stdarg.h>
55 #include <stdio.h>
56 #include <string.h>
58 #define COBJMACROS
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
62 #include "windef.h"
63 #include "winbase.h"
64 #include "winreg.h"
65 #include "winternl.h"
66 #include "winnls.h"
67 #include "wine/unicode.h"
68 #include "wingdi.h"
69 #include "winuser.h"
70 #include "winreg.h"
71 #include "commdlg.h"
72 #include "dlgs.h"
73 #include "cdlg.h"
74 #include "filedlg31.h"
75 #include "wine/debug.h"
76 #include "cderr.h"
77 #include "shellapi.h"
78 #include "shlguid.h"
79 #include "shlobj.h"
80 #include "filedlgbrowser.h"
81 #include "shlwapi.h"
83 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
85 #define UNIMPLEMENTED_FLAGS \
86 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
87 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
88 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
89 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
91 #define IsHooked(fodInfos) \
92 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
93 /***********************************************************************
94 * Data structure and global variables
96 typedef struct SFolder
98 int m_iImageIndex; /* Index of picture in image list */
99 HIMAGELIST hImgList;
100 int m_iIndent; /* Indentation index */
101 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
103 } SFOLDER,*LPSFOLDER;
105 typedef struct tagLookInInfo
107 int iMaxIndentation;
108 UINT uSelectedItem;
109 } LookInInfos;
111 typedef struct tagFD32_PRIVATE
113 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
114 } FD32_PRIVATE, *PFD32_PRIVATE;
117 /***********************************************************************
118 * Defines and global variables
121 /* Draw item constant */
122 #define ICONWIDTH 18
123 #define XTEXTOFFSET 3
125 /* AddItem flags*/
126 #define LISTEND -1
128 /* SearchItem methods */
129 #define SEARCH_PIDL 1
130 #define SEARCH_EXP 2
131 #define ITEM_NOTFOUND -1
133 /* Undefined windows message sent by CreateViewObject*/
134 #define WM_GETISHELLBROWSER WM_USER+7
136 /* NOTE
137 * Those macros exist in windowsx.h. However, you can't really use them since
138 * they rely on the UNICODE defines and can't be used inside Wine itself.
141 /* Combo box macros */
142 #define CBAddString(hwnd,str) \
143 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
144 #define CBAddStringW(hwnd,str) \
145 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
147 #define CBInsertString(hwnd,str,pos) \
148 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
150 #define CBDeleteString(hwnd,pos) \
151 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
153 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
154 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
156 #define CBGetItemDataPtr(hwnd,iItemId) \
157 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
159 #define CBGetLBText(hwnd,iItemId,str) \
160 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
162 #define CBGetCurSel(hwnd) \
163 SendMessageA(hwnd,CB_GETCURSEL,0,0);
165 #define CBSetCurSel(hwnd,pos) \
166 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
168 #define CBGetCount(hwnd) \
169 SendMessageA(hwnd,CB_GETCOUNT,0,0);
170 #define CBShowDropDown(hwnd,show) \
171 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
172 #define CBSetItemHeight(hwnd,index,height) \
173 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
175 #define CBSetExtendedUI(hwnd,flag) \
176 SendMessageA(hwnd,CB_SETEXTENDEDUI,(WPARAM)(flag),0)
178 const char *FileOpenDlgInfosStr = "FileOpenDlgInfos"; /* windows property description string */
179 const char *LookInInfosStr = "LookInInfos"; /* LOOKIN combo box property */
181 /***********************************************************************
182 * Prototypes
185 /* Internal functions used by the dialog */
186 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
187 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
188 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
189 BOOL FILEDLG95_OnOpen(HWND hwnd);
190 static LRESULT FILEDLG95_InitControls(HWND hwnd);
191 static void FILEDLG95_Clean(HWND hwnd);
193 /* Functions used by the shell navigation */
194 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
195 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
196 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
197 static void FILEDLG95_SHELL_Clean(HWND hwnd);
198 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
200 /* Functions used by the EDIT box */
201 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator);
203 /* Functions used by the filetype combo box */
204 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
205 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
206 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
207 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
209 /* Functions used by the Look In combo box */
210 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
211 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
212 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
213 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
214 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
215 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
216 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
217 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
218 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
220 /* Miscellaneous tool functions */
221 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
222 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
223 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
224 LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
226 /* Shell memory allocation */
227 static void *MemAlloc(UINT size);
228 static void MemFree(void *mem);
230 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
231 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode);
232 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
233 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
234 static BOOL BrowseSelectedFolder(HWND hwnd);
236 /***********************************************************************
237 * GetFileName95
239 * Creates an Open common dialog box that lets the user select
240 * the drive, directory, and the name of a file or set of files to open.
242 * IN : The FileOpenDlgInfos structure associated with the dialog
243 * OUT : TRUE on success
244 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
246 static BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
249 LRESULT lRes;
250 LPCVOID template;
251 HRSRC hRes;
252 HANDLE hDlgTmpl = 0;
253 HRESULT hr;
255 /* test for missing functionality */
256 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
258 FIXME("Flags 0x%08lx not yet implemented\n",
259 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
262 /* Create the dialog from a template */
264 if(!(hRes = FindResourceA(COMDLG32_hInstance,MAKEINTRESOURCEA(NEWFILEOPENORD),(LPSTR)RT_DIALOG)))
266 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
267 return FALSE;
269 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
270 !(template = LockResource( hDlgTmpl )))
272 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
273 return FALSE;
276 /* old style hook messages */
277 if (IsHooked(fodInfos))
279 fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
280 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
281 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
282 fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
285 /* Some shell namespace extensions depend on COM being initialized. */
286 hr = OleInitialize(NULL);
288 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
289 (LPDLGTEMPLATEA) template,
290 fodInfos->ofnInfos->hwndOwner,
291 FileOpenDlgProc95,
292 (LPARAM) fodInfos);
293 if (SUCCEEDED(hr))
294 OleUninitialize();
296 /* Unable to create the dialog */
297 if( lRes == -1)
298 return FALSE;
300 return lRes;
303 /***********************************************************************
304 * GetFileDialog95A
306 * Call GetFileName95 with this structure and clean the memory.
308 * IN : The OPENFILENAMEA initialisation structure passed to
309 * GetOpenFileNameA win api function (see filedlg.c)
311 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
313 BOOL ret;
314 FileOpenDlgInfos fodInfos;
315 LPSTR lpstrSavDir = NULL;
316 LPWSTR title = NULL;
317 LPWSTR defext = NULL;
318 LPWSTR filter = NULL;
319 LPWSTR customfilter = NULL;
321 /* Initialize FileOpenDlgInfos structure */
322 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
324 /* Pass in the original ofn */
325 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
327 /* save current directory */
328 if (ofn->Flags & OFN_NOCHANGEDIR)
330 lpstrSavDir = MemAlloc(MAX_PATH);
331 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
334 fodInfos.unicode = FALSE;
336 /* convert all the input strings to unicode */
337 if(ofn->lpstrInitialDir)
339 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
340 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
341 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
343 else
344 fodInfos.initdir = NULL;
346 if(ofn->lpstrFile)
348 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
349 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
351 else
352 fodInfos.filename = NULL;
354 if(ofn->lpstrDefExt)
356 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
357 defext = MemAlloc((len+1)*sizeof(WCHAR));
358 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
360 fodInfos.defext = defext;
362 if(ofn->lpstrTitle)
364 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
365 title = MemAlloc((len+1)*sizeof(WCHAR));
366 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
368 fodInfos.title = title;
370 if (ofn->lpstrFilter)
372 LPCSTR s;
373 int n, len;
375 /* filter is a list... title\0ext\0......\0\0 */
376 s = ofn->lpstrFilter;
377 while (*s) s = s+strlen(s)+1;
378 s++;
379 n = s - ofn->lpstrFilter;
380 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
381 filter = MemAlloc(len*sizeof(WCHAR));
382 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
384 fodInfos.filter = filter;
386 /* convert lpstrCustomFilter */
387 if (ofn->lpstrCustomFilter)
389 LPCSTR s;
390 int n, len;
392 /* customfilter contains a pair of strings... title\0ext\0 */
393 s = ofn->lpstrCustomFilter;
394 if (*s) s = s+strlen(s)+1;
395 if (*s) s = s+strlen(s)+1;
396 n = s - ofn->lpstrCustomFilter;
397 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
398 customfilter = MemAlloc(len*sizeof(WCHAR));
399 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
401 fodInfos.customfilter = customfilter;
403 /* Initialize the dialog property */
404 fodInfos.DlgInfos.dwDlgProp = 0;
405 fodInfos.DlgInfos.hwndCustomDlg = NULL;
407 switch(iDlgType)
409 case OPEN_DIALOG :
410 ret = GetFileName95(&fodInfos);
411 break;
412 case SAVE_DIALOG :
413 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
414 ret = GetFileName95(&fodInfos);
415 break;
416 default :
417 ret = 0;
420 if (lpstrSavDir)
422 SetCurrentDirectoryA(lpstrSavDir);
423 MemFree(lpstrSavDir);
426 if(title)
427 MemFree(title);
428 if(defext)
429 MemFree(defext);
430 if(filter)
431 MemFree(filter);
432 if(customfilter)
433 MemFree(customfilter);
434 if(fodInfos.initdir)
435 MemFree(fodInfos.initdir);
437 if(fodInfos.filename)
438 MemFree(fodInfos.filename);
440 TRACE("selected file: %s\n",ofn->lpstrFile);
442 return ret;
445 /***********************************************************************
446 * GetFileDialog95W
448 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
449 * Call GetFileName95 with this structure and clean the memory.
452 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
454 BOOL ret;
455 FileOpenDlgInfos fodInfos;
456 LPWSTR lpstrSavDir = NULL;
458 /* Initialize FileOpenDlgInfos structure */
459 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
461 /* Pass in the original ofn */
462 fodInfos.ofnInfos = ofn;
464 fodInfos.title = ofn->lpstrTitle;
465 fodInfos.defext = ofn->lpstrDefExt;
466 fodInfos.filter = ofn->lpstrFilter;
467 fodInfos.customfilter = ofn->lpstrCustomFilter;
469 /* convert string arguments, save others */
470 if(ofn->lpstrFile)
472 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
473 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
475 else
476 fodInfos.filename = NULL;
478 if(ofn->lpstrInitialDir)
480 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
481 DWORD len = strlenW(ofn->lpstrInitialDir)+1;
482 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
483 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
485 else
486 fodInfos.initdir = NULL;
488 /* save current directory */
489 if (ofn->Flags & OFN_NOCHANGEDIR)
491 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
492 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
495 fodInfos.unicode = TRUE;
497 switch(iDlgType)
499 case OPEN_DIALOG :
500 ret = GetFileName95(&fodInfos);
501 break;
502 case SAVE_DIALOG :
503 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
504 ret = GetFileName95(&fodInfos);
505 break;
506 default :
507 ret = 0;
510 if (lpstrSavDir)
512 SetCurrentDirectoryW(lpstrSavDir);
513 MemFree(lpstrSavDir);
516 /* restore saved IN arguments and convert OUT arguments back */
517 MemFree(fodInfos.filename);
518 MemFree(fodInfos.initdir);
519 return ret;
522 /******************************************************************************
523 * COMDLG32_GetDisplayNameOf [internal]
525 * Helper function to get the display name for a pidl.
527 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
528 LPSHELLFOLDER psfDesktop;
529 STRRET strret;
531 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
532 return FALSE;
534 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
535 IShellFolder_Release(psfDesktop);
536 return FALSE;
539 IShellFolder_Release(psfDesktop);
540 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
543 /***********************************************************************
544 * ArrangeCtrlPositions [internal]
546 * NOTE: Do not change anything here without a lot of testing.
548 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
550 HWND hwndChild, hwndStc32;
551 RECT rectParent, rectChild, rectStc32;
552 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
554 /* Take into account if open as read only checkbox and help button
555 * are hidden
557 if (hide_help)
559 RECT rectHelp, rectCancel;
560 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
561 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
562 /* subtract the height of the help button plus the space between
563 * the help button and the cancel button to the height of the dialog
565 help_fixup = rectHelp.bottom - rectCancel.bottom;
569 There are two possibilities to add components to the default file dialog box.
571 By default, all the new components are added below the standard dialog box (the else case).
573 However, if there is a static text component with the stc32 id, a special case happens.
574 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
575 in the window and the cx and cy indicate how to size the window.
576 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
577 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
581 GetClientRect(hwndParentDlg, &rectParent);
583 /* when arranging controls we have to use fixed parent size */
584 rectParent.bottom -= help_fixup;
586 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
587 if (hwndStc32)
589 GetWindowRect(hwndStc32, &rectStc32);
590 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
592 /* set the size of the stc32 control according to the size of
593 * client area of the parent dialog
595 SetWindowPos(hwndStc32, 0,
596 0, 0,
597 rectParent.right, rectParent.bottom,
598 SWP_NOMOVE | SWP_NOZORDER);
600 else
601 SetRectEmpty(&rectStc32);
603 /* this part moves controls of the child dialog */
604 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
605 while (hwndChild)
607 if (hwndChild != hwndStc32)
609 GetWindowRect(hwndChild, &rectChild);
610 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
612 /* move only if stc32 exist */
613 if (hwndStc32 && rectChild.left > rectStc32.right)
615 LONG old_left = rectChild.left;
617 /* move to the right of visible controls of the parent dialog */
618 rectChild.left += rectParent.right;
619 rectChild.left -= rectStc32.right;
621 child_width_fixup = rectChild.left - old_left;
623 /* move even if stc32 doesn't exist */
624 if (rectChild.top >= rectStc32.bottom)
626 LONG old_top = rectChild.top;
628 /* move below visible controls of the parent dialog */
629 rectChild.top += rectParent.bottom;
630 rectChild.top -= rectStc32.bottom - rectStc32.top;
632 child_height_fixup = rectChild.top - old_top;
635 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
636 0, 0, SWP_NOSIZE | SWP_NOZORDER);
638 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
641 /* this part moves controls of the parent dialog */
642 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
643 while (hwndChild)
645 if (hwndChild != hwndChildDlg)
647 GetWindowRect(hwndChild, &rectChild);
648 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
650 /* left,top of stc32 marks the position of controls
651 * from the parent dialog
653 rectChild.left += rectStc32.left;
654 rectChild.top += rectStc32.top;
656 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
657 0, 0, SWP_NOSIZE | SWP_NOZORDER);
659 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
662 /* calculate the size of the resulting dialog */
664 /* here we have to use original parent size */
665 GetClientRect(hwndParentDlg, &rectParent);
666 GetClientRect(hwndChildDlg, &rectChild);
668 if (hwndStc32)
670 rectChild.right += child_width_fixup;
671 rectChild.bottom += child_height_fixup;
673 if (rectParent.right > rectChild.right)
675 rectParent.right += rectChild.right;
676 rectParent.right -= rectStc32.right - rectStc32.left;
678 else
680 rectParent.right = rectChild.right;
683 if (rectParent.bottom > rectChild.bottom)
685 rectParent.bottom += rectChild.bottom;
686 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
688 else
690 /* child dialog is higher, unconditionally set new dialog
691 * height to its size (help_fixup will be subtracted below)
693 rectParent.bottom = rectChild.bottom + help_fixup;
696 else
698 rectParent.bottom += rectChild.bottom;
701 /* finally use fixed parent size */
702 rectParent.bottom -= help_fixup;
704 /* set the size of the parent dialog */
705 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
706 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
707 SetWindowPos(hwndParentDlg, 0,
708 0, 0,
709 rectParent.right - rectParent.left,
710 rectParent.bottom - rectParent.top,
711 SWP_NOMOVE | SWP_NOZORDER);
714 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
716 switch(uMsg) {
717 case WM_INITDIALOG:
718 return TRUE;
720 return FALSE;
723 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
725 LPCVOID template;
726 HRSRC hRes;
727 HANDLE hDlgTmpl = 0;
728 HWND hChildDlg = 0;
730 TRACE("\n");
733 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
734 * structure's hInstance parameter is not a HINSTANCE, but
735 * instead a pointer to a template resource to use.
737 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
739 HINSTANCE hinst;
740 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
742 hinst = COMDLG32_hInstance;
743 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
745 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
746 return NULL;
749 else
751 hinst = fodInfos->ofnInfos->hInstance;
752 if(fodInfos->unicode)
754 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
755 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
757 else
759 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
760 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
762 if (!hRes)
764 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
765 return NULL;
767 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
768 !(template = LockResource( hDlgTmpl )))
770 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
771 return NULL;
774 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
775 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
776 (LPARAM)fodInfos->ofnInfos);
777 if(hChildDlg)
779 ShowWindow(hChildDlg,SW_SHOW);
780 return hChildDlg;
783 else if( IsHooked(fodInfos))
785 RECT rectHwnd;
786 struct {
787 DLGTEMPLATE tmplate;
788 WORD menu,class,title;
789 } temp;
790 GetClientRect(hwnd,&rectHwnd);
791 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
792 temp.tmplate.dwExtendedStyle = 0;
793 temp.tmplate.cdit = 0;
794 temp.tmplate.x = 0;
795 temp.tmplate.y = 0;
796 temp.tmplate.cx = 0;
797 temp.tmplate.cy = 0;
798 temp.menu = temp.class = temp.title = 0;
800 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
801 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
803 return hChildDlg;
805 return NULL;
808 /***********************************************************************
809 * SendCustomDlgNotificationMessage
811 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
814 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
816 LRESULT hook_result = 0;
818 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
820 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
822 if(!fodInfos) return 0;
824 if(fodInfos->DlgInfos.hwndCustomDlg)
826 TRACE("CALL NOTIFY for %x\n", uCode);
827 if(fodInfos->unicode)
829 OFNOTIFYW ofnNotify;
830 ofnNotify.hdr.hwndFrom=hwndParentDlg;
831 ofnNotify.hdr.idFrom=0;
832 ofnNotify.hdr.code = uCode;
833 ofnNotify.lpOFN = fodInfos->ofnInfos;
834 ofnNotify.pszFile = NULL;
835 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
837 else
839 OFNOTIFYA ofnNotify;
840 ofnNotify.hdr.hwndFrom=hwndParentDlg;
841 ofnNotify.hdr.idFrom=0;
842 ofnNotify.hdr.code = uCode;
843 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
844 ofnNotify.pszFile = NULL;
845 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
847 TRACE("RET NOTIFY\n");
849 TRACE("Retval: 0x%08lx\n", hook_result);
850 return hook_result;
853 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer)
855 UINT sizeUsed = 0, n, total;
856 LPWSTR lpstrFileList = NULL;
857 WCHAR lpstrCurrentDir[MAX_PATH];
858 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
860 TRACE("CDM_GETFILEPATH:\n");
862 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
863 return -1;
865 /* get path and filenames */
866 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrCurrentDir);
867 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
869 TRACE("path >%s< filespec >%s< %d files\n",
870 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
872 if( fodInfos->unicode )
874 LPWSTR bufW = buffer;
875 total = strlenW(lpstrCurrentDir) + 1 + sizeUsed;
877 /* Prepend the current path */
878 n = strlenW(lpstrCurrentDir) + 1;
879 memcpy( bufW, lpstrCurrentDir, min(n,size) * sizeof(WCHAR));
880 if(n<size)
882 /* 'n' includes trailing \0 */
883 bufW[n-1] = '\\';
884 memcpy( &bufW[n], lpstrFileList, (size-n)*sizeof(WCHAR) );
886 TRACE("returned -> %s\n",debugstr_wn(bufW, total));
888 else
890 LPSTR bufA = buffer;
891 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
892 NULL, 0, NULL, NULL);
893 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
894 NULL, 0, NULL, NULL);
896 /* Prepend the current path */
897 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
898 bufA, size, NULL, NULL);
900 if(n<size)
902 /* 'n' includes trailing \0 */
903 bufA[n-1] = '\\';
904 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
905 &bufA[n], size-n, NULL, NULL);
908 TRACE("returned -> %s\n",debugstr_an(bufA, total));
910 MemFree(lpstrFileList);
912 return total;
915 static INT_PTR FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer)
917 UINT sizeUsed = 0;
918 LPWSTR lpstrFileList = NULL;
919 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
921 TRACE("CDM_GETSPEC:\n");
923 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
924 if( fodInfos->unicode )
926 LPWSTR bufW = buffer;
927 memcpy( bufW, lpstrFileList, sizeof(WCHAR)*sizeUsed );
929 else
931 LPSTR bufA = buffer;
932 sizeUsed = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed,
933 NULL, 0, NULL, NULL);
934 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
935 bufA, size, NULL, NULL);
937 MemFree(lpstrFileList);
939 return sizeUsed;
942 /***********************************************************************
943 * FILEDLG95_HandleCustomDialogMessages
945 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
947 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
949 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
950 WCHAR lpstrPath[MAX_PATH];
951 INT_PTR retval;
953 if(!fodInfos) return FALSE;
955 switch(uMsg)
957 case CDM_GETFILEPATH:
958 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
959 break;
961 case CDM_GETFOLDERPATH:
962 TRACE("CDM_GETFOLDERPATH:\n");
963 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
964 if (lParam)
966 if (fodInfos->unicode)
967 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
968 else
969 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
970 (LPSTR)lParam, (int)wParam, NULL, NULL);
972 retval = strlenW(lpstrPath);
973 break;
975 case CDM_GETSPEC:
976 retval = FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
977 break;
979 case CDM_SETCONTROLTEXT:
980 TRACE("CDM_SETCONTROLTEXT:\n");
981 if ( lParam )
983 if( fodInfos->unicode )
984 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
985 else
986 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
988 retval = TRUE;
989 break;
991 case CDM_HIDECONTROL:
992 /* MSDN states that it should fail for not OFN_EXPLORER case */
993 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
995 HWND control = GetDlgItem( hwnd, wParam );
996 if (control) ShowWindow( control, SW_HIDE );
997 retval = TRUE;
999 else retval = FALSE;
1000 break;
1002 default:
1003 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1004 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1005 return FALSE;
1007 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1008 return TRUE;
1011 /***********************************************************************
1012 * FileOpenDlgProc95
1014 * File open dialog procedure
1016 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1018 #if 0
1019 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
1020 #endif
1022 switch(uMsg)
1024 case WM_INITDIALOG:
1026 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1028 /* Adds the FileOpenDlgInfos in the property list of the dialog
1029 so it will be easily accessible through a GetPropA(...) */
1030 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
1032 fodInfos->DlgInfos.hwndCustomDlg =
1033 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1035 FILEDLG95_InitControls(hwnd);
1037 if (fodInfos->DlgInfos.hwndCustomDlg)
1039 RECT rc;
1040 UINT flags = SWP_NOACTIVATE;
1042 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1043 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1045 /* resize the custom dialog to the parent size */
1046 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1047 GetClientRect(hwnd, &rc);
1048 else
1050 /* our own fake template is zero sized and doesn't have
1051 * children, so there is no need to resize it.
1052 * Picasa depends on it.
1054 flags |= SWP_NOSIZE;
1055 SetRectEmpty(&rc);
1057 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1058 0, 0, rc.right, rc.bottom, flags);
1061 FILEDLG95_FillControls(hwnd, wParam, lParam);
1063 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1064 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1065 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1066 return 0;
1068 case WM_COMMAND:
1069 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1070 case WM_DRAWITEM:
1072 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1074 case IDC_LOOKIN:
1075 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1076 return TRUE;
1079 return FALSE;
1081 case WM_GETISHELLBROWSER:
1082 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1084 case WM_DESTROY:
1085 RemovePropA(hwnd, FileOpenDlgInfosStr);
1086 return FALSE;
1088 case WM_NOTIFY:
1090 LPNMHDR lpnmh = (LPNMHDR)lParam;
1091 UINT stringId = -1;
1093 /* set up the button tooltips strings */
1094 if(TTN_GETDISPINFOA == lpnmh->code )
1096 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1097 switch(lpnmh->idFrom )
1099 /* Up folder button */
1100 case FCIDM_TB_UPFOLDER:
1101 stringId = IDS_UPFOLDER;
1102 break;
1103 /* New folder button */
1104 case FCIDM_TB_NEWFOLDER:
1105 stringId = IDS_NEWFOLDER;
1106 break;
1107 /* List option button */
1108 case FCIDM_TB_SMALLICON:
1109 stringId = IDS_LISTVIEW;
1110 break;
1111 /* Details option button */
1112 case FCIDM_TB_REPORTVIEW:
1113 stringId = IDS_REPORTVIEW;
1114 break;
1115 /* Desktop button */
1116 case FCIDM_TB_DESKTOP:
1117 stringId = IDS_TODESKTOP;
1118 break;
1119 default:
1120 stringId = 0;
1122 lpdi->hinst = COMDLG32_hInstance;
1123 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1125 return FALSE;
1127 default :
1128 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1129 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1130 return FALSE;
1134 /***********************************************************************
1135 * FILEDLG95_InitControls
1137 * WM_INITDIALOG message handler (before hook notification)
1139 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1141 int win2000plus = 0;
1142 int win98plus = 0;
1143 int handledPath = FALSE;
1144 OSVERSIONINFOA osVi;
1145 static const WCHAR szwSlash[] = { '\\', 0 };
1146 static const WCHAR szwStar[] = { '*',0 };
1148 TBBUTTON tbb[] =
1150 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1151 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1152 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1153 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1154 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1155 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1156 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1157 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1158 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1160 TBADDBITMAP tba[2];
1161 RECT rectTB;
1162 RECT rectlook;
1163 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1165 tba[0].hInst = HINST_COMMCTRL;
1166 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1167 tba[1].hInst = COMDLG32_hInstance;
1168 tba[1].nID = 800;
1170 TRACE("%p\n", fodInfos);
1172 /* Get windows version emulating */
1173 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1174 GetVersionExA(&osVi);
1175 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1176 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1177 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1178 win2000plus = (osVi.dwMajorVersion > 4);
1179 if (win2000plus) win98plus = TRUE;
1181 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1183 /* Get the hwnd of the controls */
1184 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1185 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1186 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1188 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1189 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1191 /* construct the toolbar */
1192 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1193 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1195 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1196 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1197 rectTB.left = rectlook.right;
1198 rectTB.top = rectlook.top-1;
1200 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1201 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1202 rectTB.left, rectTB.top,
1203 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1204 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1206 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1208 /* FIXME: use TB_LOADIMAGES when implemented */
1209 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1210 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1211 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1213 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1214 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1216 /* Set the window text with the text specified in the OPENFILENAME structure */
1217 if(fodInfos->title)
1219 SetWindowTextW(hwnd,fodInfos->title);
1221 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1223 WCHAR buf[16];
1224 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1225 SetWindowTextW(hwnd, buf);
1228 /* Initialise the file name edit control */
1229 handledPath = FALSE;
1230 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1232 if(fodInfos->filename)
1234 /* 1. If win2000 or higher and filename contains a path, use it
1235 in preference over the lpstrInitialDir */
1236 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1237 WCHAR tmpBuf[MAX_PATH];
1238 WCHAR *nameBit;
1239 DWORD result;
1241 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1242 if (result) {
1244 /* nameBit is always shorter than the original filename */
1245 strcpyW(fodInfos->filename,nameBit);
1247 *nameBit = 0x00;
1248 if (fodInfos->initdir == NULL)
1249 MemFree(fodInfos->initdir);
1250 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1251 strcpyW(fodInfos->initdir, tmpBuf);
1252 handledPath = TRUE;
1253 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1254 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1256 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1258 } else {
1259 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1263 /* 2. (All platforms) If initdir is not null, then use it */
1264 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1265 (*fodInfos->initdir!=0x00))
1267 /* Work out the proper path as supplied one might be relative */
1268 /* (Here because supplying '.' as dir browses to My Computer) */
1269 if (handledPath==FALSE) {
1270 WCHAR tmpBuf[MAX_PATH];
1271 WCHAR tmpBuf2[MAX_PATH];
1272 WCHAR *nameBit;
1273 DWORD result;
1275 strcpyW(tmpBuf, fodInfos->initdir);
1276 if( PathFileExistsW(tmpBuf) ) {
1277 /* initdir does not have to be a directory. If a file is
1278 * specified, the dir part is taken */
1279 if( PathIsDirectoryW(tmpBuf)) {
1280 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1281 strcatW(tmpBuf, szwSlash);
1283 strcatW(tmpBuf, szwStar);
1285 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1286 if (result) {
1287 *nameBit = 0x00;
1288 if (fodInfos->initdir)
1289 MemFree(fodInfos->initdir);
1290 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1291 strcpyW(fodInfos->initdir, tmpBuf2);
1292 handledPath = TRUE;
1293 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1296 else if (fodInfos->initdir)
1298 MemFree(fodInfos->initdir);
1299 fodInfos->initdir = NULL;
1300 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1305 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1306 (*fodInfos->initdir==0x00)))
1308 /* 3. All except w2k+: if filename contains a path use it */
1309 if (!win2000plus && fodInfos->filename &&
1310 *fodInfos->filename &&
1311 strpbrkW(fodInfos->filename, szwSlash)) {
1312 WCHAR tmpBuf[MAX_PATH];
1313 WCHAR *nameBit;
1314 DWORD result;
1316 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1317 tmpBuf, &nameBit);
1318 if (result) {
1319 int len;
1321 /* nameBit is always shorter than the original filename */
1322 strcpyW(fodInfos->filename, nameBit);
1323 *nameBit = 0x00;
1325 len = strlenW(tmpBuf);
1326 if(fodInfos->initdir)
1327 MemFree(fodInfos->initdir);
1328 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1329 strcpyW(fodInfos->initdir, tmpBuf);
1331 handledPath = TRUE;
1332 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1333 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1335 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1338 /* 4. win98+ and win2000+ if any files of specified filter types in
1339 current directory, use it */
1340 if ( win98plus && handledPath == FALSE &&
1341 fodInfos->filter && *fodInfos->filter) {
1343 BOOL searchMore = TRUE;
1344 LPCWSTR lpstrPos = fodInfos->filter;
1345 WIN32_FIND_DATAW FindFileData;
1346 HANDLE hFind;
1348 while (searchMore)
1350 /* filter is a list... title\0ext\0......\0\0 */
1352 /* Skip the title */
1353 if(! *lpstrPos) break; /* end */
1354 lpstrPos += strlenW(lpstrPos) + 1;
1356 /* See if any files exist in the current dir with this extension */
1357 if(! *lpstrPos) break; /* end */
1359 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1361 if (hFind == INVALID_HANDLE_VALUE) {
1362 /* None found - continue search */
1363 lpstrPos += strlenW(lpstrPos) + 1;
1365 } else {
1366 searchMore = FALSE;
1368 if(fodInfos->initdir)
1369 MemFree(fodInfos->initdir);
1370 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1371 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1373 handledPath = TRUE;
1374 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1375 debugstr_w(lpstrPos));
1376 break;
1381 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1383 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1384 if (handledPath == FALSE && (win2000plus || win98plus)) {
1385 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1387 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1389 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1391 /* last fallback */
1392 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1393 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1394 } else {
1395 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1397 } else {
1398 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1400 handledPath = TRUE;
1401 } else if (handledPath==FALSE) {
1402 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1403 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1404 handledPath = TRUE;
1405 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1408 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1409 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1411 /* Must the open as read only check box be checked ?*/
1412 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1414 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1417 /* Must the open as read only check box be hidden? */
1418 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1420 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1421 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1424 /* Must the help button be hidden? */
1425 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1427 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1428 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1431 /* Resize the height, if open as read only checkbox ad help button
1432 are hidden and we are not using a custom template nor a customDialog
1434 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1435 (!(fodInfos->ofnInfos->Flags &
1436 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1437 (!fodInfos->DlgInfos.hwndCustomDlg ))
1439 RECT rectDlg, rectHelp, rectCancel;
1440 GetWindowRect(hwnd, &rectDlg);
1441 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1442 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1443 /* subtract the height of the help button plus the space between
1444 the help button and the cancel button to the height of the dialog */
1445 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1446 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1447 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1449 /* change Open to Save */
1450 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1452 WCHAR buf[16];
1453 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1454 SetDlgItemTextW(hwnd, IDOK, buf);
1455 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1456 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1458 return 0;
1461 /***********************************************************************
1462 * FILEDLG95_FillControls
1464 * WM_INITDIALOG message handler (after hook notification)
1466 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1468 LPITEMIDLIST pidlItemId = NULL;
1470 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1472 TRACE("dir=%s file=%s\n",
1473 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1475 /* Get the initial directory pidl */
1477 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1479 WCHAR path[MAX_PATH];
1481 GetCurrentDirectoryW(MAX_PATH,path);
1482 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1485 /* Initialise shell objects */
1486 FILEDLG95_SHELL_Init(hwnd);
1488 /* Initialize the Look In combo box */
1489 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1491 /* Initialize the filter combo box */
1492 FILEDLG95_FILETYPE_Init(hwnd);
1494 /* Browse to the initial directory */
1495 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1497 /* Free pidlItem memory */
1498 COMDLG32_SHFree(pidlItemId);
1500 return TRUE;
1502 /***********************************************************************
1503 * FILEDLG95_Clean
1505 * Regroups all the cleaning functions of the filedlg
1507 void FILEDLG95_Clean(HWND hwnd)
1509 FILEDLG95_FILETYPE_Clean(hwnd);
1510 FILEDLG95_LOOKIN_Clean(hwnd);
1511 FILEDLG95_SHELL_Clean(hwnd);
1513 /***********************************************************************
1514 * FILEDLG95_OnWMCommand
1516 * WM_COMMAND message handler
1518 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1520 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1521 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1522 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1524 switch(wID)
1526 /* OK button */
1527 case IDOK:
1528 FILEDLG95_OnOpen(hwnd);
1529 break;
1530 /* Cancel button */
1531 case IDCANCEL:
1532 FILEDLG95_Clean(hwnd);
1533 EndDialog(hwnd, FALSE);
1534 break;
1535 /* Filetype combo box */
1536 case IDC_FILETYPE:
1537 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1538 break;
1539 /* LookIn combo box */
1540 case IDC_LOOKIN:
1541 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1542 break;
1544 /* --- toolbar --- */
1545 /* Up folder button */
1546 case FCIDM_TB_UPFOLDER:
1547 FILEDLG95_SHELL_UpFolder(hwnd);
1548 break;
1549 /* New folder button */
1550 case FCIDM_TB_NEWFOLDER:
1551 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1552 break;
1553 /* List option button */
1554 case FCIDM_TB_SMALLICON:
1555 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1556 break;
1557 /* Details option button */
1558 case FCIDM_TB_REPORTVIEW:
1559 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1560 break;
1561 /* Details option button */
1562 case FCIDM_TB_DESKTOP:
1563 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1564 break;
1566 case IDC_FILENAME:
1567 break;
1570 /* Do not use the listview selection anymore */
1571 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1572 return 0;
1575 /***********************************************************************
1576 * FILEDLG95_OnWMGetIShellBrowser
1578 * WM_GETISHELLBROWSER message handler
1580 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1583 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1585 TRACE("\n");
1587 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1589 return TRUE;
1593 /***********************************************************************
1594 * FILEDLG95_SendFileOK
1596 * Sends the CDN_FILEOK notification if required
1598 * RETURNS
1599 * TRUE if the dialog should close
1600 * FALSE if the dialog should not be closed
1602 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1604 /* ask the hook if we can close */
1605 if(IsHooked(fodInfos))
1607 LRESULT retval;
1609 TRACE("---\n");
1610 /* First send CDN_FILEOK as MSDN doc says */
1611 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1612 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1614 TRACE("canceled\n");
1615 return (retval == 0);
1618 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1619 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1620 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1621 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1623 TRACE("canceled\n");
1624 return (retval == 0);
1627 return TRUE;
1630 /***********************************************************************
1631 * FILEDLG95_OnOpenMultipleFiles
1633 * Handles the opening of multiple files.
1635 * FIXME
1636 * check destination buffer size
1638 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1640 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1641 UINT nCount, nSizePath;
1642 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1644 TRACE("\n");
1646 if(fodInfos->unicode)
1648 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1649 ofn->lpstrFile[0] = '\0';
1651 else
1653 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1654 ofn->lpstrFile[0] = '\0';
1657 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1659 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1660 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1661 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1663 LPWSTR lpstrTemp = lpstrFileList;
1665 for ( nCount = 0; nCount < nFileCount; nCount++ )
1667 LPITEMIDLIST pidl;
1669 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1670 if (!pidl)
1672 WCHAR lpstrNotFound[100];
1673 WCHAR lpstrMsg[100];
1674 WCHAR tmp[400];
1675 static const WCHAR nl[] = {'\n',0};
1677 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1678 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1680 strcpyW(tmp, lpstrTemp);
1681 strcatW(tmp, nl);
1682 strcatW(tmp, lpstrNotFound);
1683 strcatW(tmp, nl);
1684 strcatW(tmp, lpstrMsg);
1686 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1687 return FALSE;
1690 /* move to the next file in the list of files */
1691 lpstrTemp += strlenW(lpstrTemp) + 1;
1692 COMDLG32_SHFree(pidl);
1696 nSizePath = strlenW(lpstrPathSpec) + 1;
1697 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1699 /* For "oldstyle" dialog the components have to
1700 be separated by blanks (not '\0'!) and short
1701 filenames have to be used! */
1702 FIXME("Components have to be separated by blanks\n");
1704 if(fodInfos->unicode)
1706 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1707 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1708 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1710 else
1712 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1714 if (ofn->lpstrFile != NULL)
1716 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1717 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1718 if (ofn->nMaxFile > nSizePath)
1720 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1721 ofn->lpstrFile + nSizePath,
1722 ofn->nMaxFile - nSizePath, NULL, NULL);
1727 fodInfos->ofnInfos->nFileOffset = nSizePath;
1728 fodInfos->ofnInfos->nFileExtension = 0;
1730 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1731 return FALSE;
1733 /* clean and exit */
1734 FILEDLG95_Clean(hwnd);
1735 return EndDialog(hwnd,TRUE);
1738 /***********************************************************************
1739 * FILEDLG95_OnOpen
1741 * Ok button WM_COMMAND message handler
1743 * If the function succeeds, the return value is nonzero.
1745 #define ONOPEN_BROWSE 1
1746 #define ONOPEN_OPEN 2
1747 #define ONOPEN_SEARCH 3
1748 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1750 WCHAR strMsgTitle[MAX_PATH];
1751 WCHAR strMsgText [MAX_PATH];
1752 if (idCaption)
1753 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1754 else
1755 strMsgTitle[0] = '\0';
1756 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1757 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1760 BOOL FILEDLG95_OnOpen(HWND hwnd)
1762 LPWSTR lpstrFileList;
1763 UINT nFileCount = 0;
1764 UINT sizeUsed = 0;
1765 BOOL ret = TRUE;
1766 WCHAR lpstrPathAndFile[MAX_PATH];
1767 WCHAR lpstrTemp[MAX_PATH];
1768 LPSHELLFOLDER lpsf = NULL;
1769 int nOpenAction;
1770 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1772 TRACE("hwnd=%p\n", hwnd);
1774 /* get the files from the edit control */
1775 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1777 /* try if the user selected a folder in the shellview */
1778 if(nFileCount == 0)
1780 BrowseSelectedFolder(hwnd);
1781 return FALSE;
1784 if(nFileCount > 1)
1786 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1787 goto ret;
1790 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1793 Step 1: Build a complete path name from the current folder and
1794 the filename or path in the edit box.
1795 Special cases:
1796 - the path in the edit box is a root path
1797 (with or without drive letter)
1798 - the edit box contains ".." (or a path with ".." in it)
1801 /* Get the current directory name */
1802 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1804 /* last fallback */
1805 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1807 PathAddBackslashW(lpstrPathAndFile);
1809 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1811 /* if the user specifyed a fully qualified path use it */
1812 if(PathIsRelativeW(lpstrFileList))
1814 strcatW(lpstrPathAndFile, lpstrFileList);
1816 else
1818 /* does the path have a drive letter? */
1819 if (PathGetDriveNumberW(lpstrFileList) == -1)
1820 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1821 else
1822 strcpyW(lpstrPathAndFile, lpstrFileList);
1825 /* resolve "." and ".." */
1826 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1827 strcpyW(lpstrPathAndFile, lpstrTemp);
1828 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1830 MemFree(lpstrFileList);
1833 Step 2: here we have a cleaned up path
1835 We have to parse the path step by step to see if we have to browse
1836 to a folder if the path points to a directory or the last
1837 valid element is a directory.
1839 valid variables:
1840 lpstrPathAndFile: cleaned up path
1843 if (nFileCount &&
1844 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1845 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1846 nOpenAction = ONOPEN_OPEN;
1847 else
1848 nOpenAction = ONOPEN_BROWSE;
1850 /* don't apply any checks with OFN_NOVALIDATE */
1852 LPWSTR lpszTemp, lpszTemp1;
1853 LPITEMIDLIST pidl = NULL;
1854 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1856 /* check for invalid chars */
1857 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1859 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1860 ret = FALSE;
1861 goto ret;
1864 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1866 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1867 while (lpszTemp1)
1869 LPSHELLFOLDER lpsfChild;
1870 WCHAR lpwstrTemp[MAX_PATH];
1871 DWORD dwEaten, dwAttributes;
1872 LPWSTR p;
1874 strcpyW(lpwstrTemp, lpszTemp);
1875 p = PathFindNextComponentW(lpwstrTemp);
1877 if (!p) break; /* end of path */
1879 *p = 0;
1880 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1882 /* There are no wildcards when OFN_NOVALIDATE is set */
1883 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1885 static const WCHAR wszWild[] = { '*', '?', 0 };
1886 /* if the last element is a wildcard do a search */
1887 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1889 nOpenAction = ONOPEN_SEARCH;
1890 break;
1893 lpszTemp1 = lpszTemp;
1895 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1897 /* append a backslash to drive letters */
1898 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1899 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1900 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1902 PathAddBackslashW(lpwstrTemp);
1905 dwAttributes = SFGAO_FOLDER;
1906 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1908 /* the path component is valid, we have a pidl of the next path component */
1909 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1910 if(dwAttributes & SFGAO_FOLDER)
1912 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1914 ERR("bind to failed\n"); /* should not fail */
1915 break;
1917 IShellFolder_Release(lpsf);
1918 lpsf = lpsfChild;
1919 lpsfChild = NULL;
1921 else
1923 TRACE("value\n");
1925 /* end dialog, return value */
1926 nOpenAction = ONOPEN_OPEN;
1927 break;
1929 COMDLG32_SHFree(pidl);
1930 pidl = NULL;
1932 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1934 if(*lpszTemp) /* points to trailing null for last path element */
1936 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1938 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1939 break;
1942 else
1944 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1945 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1947 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1948 break;
1951 /* change to the current folder */
1952 nOpenAction = ONOPEN_OPEN;
1953 break;
1955 else
1957 nOpenAction = ONOPEN_OPEN;
1958 break;
1961 if(pidl) COMDLG32_SHFree(pidl);
1965 Step 3: here we have a cleaned up and validated path
1967 valid variables:
1968 lpsf: ShellFolder bound to the rightmost valid path component
1969 lpstrPathAndFile: cleaned up path
1970 nOpenAction: action to do
1972 TRACE("end validate sf=%p\n", lpsf);
1974 switch(nOpenAction)
1976 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1977 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1979 int iPos;
1980 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1981 DWORD len;
1983 /* replace the current filter */
1984 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1985 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1986 len = strlenW(lpszTemp)+1;
1987 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1988 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1990 /* set the filter cb to the extension when possible */
1991 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1992 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1994 /* fall through */
1995 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1996 TRACE("ONOPEN_BROWSE\n");
1998 IPersistFolder2 * ppf2;
1999 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2001 LPITEMIDLIST pidlCurrent;
2002 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2003 IPersistFolder2_Release(ppf2);
2004 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2006 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
2008 else if( nOpenAction == ONOPEN_SEARCH )
2010 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2012 COMDLG32_SHFree(pidlCurrent);
2015 ret = FALSE;
2016 break;
2017 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2018 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2020 WCHAR *ext = NULL;
2022 /* update READONLY check box flag */
2023 if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2024 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2025 else
2026 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2028 /* Attach the file extension with file name*/
2029 ext = PathFindExtensionW(lpstrPathAndFile);
2030 if (! *ext)
2032 /* if no extension is specified with file name, then */
2033 /* attach the extension from file filter or default one */
2035 WCHAR *filterExt = NULL;
2036 LPWSTR lpstrFilter = NULL;
2037 static const WCHAR szwDot[] = {'.',0};
2038 int PathLength = strlenW(lpstrPathAndFile);
2040 /* Attach the dot*/
2041 strcatW(lpstrPathAndFile, szwDot);
2043 /*Get the file extension from file type filter*/
2044 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2045 fodInfos->ofnInfos->nFilterIndex-1);
2047 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2048 filterExt = PathFindExtensionW(lpstrFilter);
2050 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2051 strcatW(lpstrPathAndFile, filterExt + 1);
2052 else if ( fodInfos->defext ) /* attach the default file extension*/
2053 strcatW(lpstrPathAndFile, fodInfos->defext);
2055 /* In Open dialog: if file does not exist try without extension */
2056 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2057 lpstrPathAndFile[PathLength] = '\0';
2060 if (fodInfos->defext) /* add default extension */
2062 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2063 if (*ext)
2064 ext++;
2065 if (!lstrcmpiW(fodInfos->defext, ext))
2066 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2067 else
2068 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2071 /* In Save dialog: check if the file already exists */
2072 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2073 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2074 && PathFileExistsW(lpstrPathAndFile))
2076 WCHAR lpstrOverwrite[100];
2077 int answer;
2079 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2080 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2081 MB_YESNO | MB_ICONEXCLAMATION);
2082 if (answer == IDNO)
2084 ret = FALSE;
2085 goto ret;
2089 /* Check that the size of the file does not exceed buffer size.
2090 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2091 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2092 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2094 LPWSTR lpszTemp;
2096 /* fill destination buffer */
2097 if (fodInfos->ofnInfos->lpstrFile)
2099 if(fodInfos->unicode)
2101 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2103 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2104 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2105 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2107 else
2109 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2111 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2112 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2113 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2114 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2118 /* set filename offset */
2119 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2120 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2122 /* set extension offset */
2123 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2124 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2126 /* set the lpstrFileTitle */
2127 if(fodInfos->ofnInfos->lpstrFileTitle)
2129 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2130 if(fodInfos->unicode)
2132 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2133 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2135 else
2137 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2138 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2139 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2143 /* copy currently selected filter to lpstrCustomFilter */
2144 if (fodInfos->ofnInfos->lpstrCustomFilter)
2146 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2147 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2148 NULL, 0, NULL, NULL);
2149 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2151 LPSTR s = ofn->lpstrCustomFilter;
2152 s += strlen(ofn->lpstrCustomFilter)+1;
2153 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2154 s, len, NULL, NULL);
2159 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2160 goto ret;
2162 TRACE("close\n");
2163 FILEDLG95_Clean(hwnd);
2164 ret = EndDialog(hwnd, TRUE);
2166 else
2168 WORD size;
2170 size = strlenW(lpstrPathAndFile) + 1;
2171 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2172 size += 1;
2173 /* return needed size in first two bytes of lpstrFile */
2174 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2175 FILEDLG95_Clean(hwnd);
2176 ret = EndDialog(hwnd, FALSE);
2177 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2179 goto ret;
2181 break;
2184 ret:
2185 if(lpsf) IShellFolder_Release(lpsf);
2186 return ret;
2189 /***********************************************************************
2190 * FILEDLG95_SHELL_Init
2192 * Initialisation of the shell objects
2194 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2196 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2198 TRACE("\n");
2201 * Initialisation of the FileOpenDialogInfos structure
2204 /* Shell */
2206 /*ShellInfos */
2207 fodInfos->ShellInfos.hwndOwner = hwnd;
2209 /* Disable multi-select if flag not set */
2210 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2212 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2214 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2215 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2217 /* Construct the IShellBrowser interface */
2218 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2220 return NOERROR;
2223 /***********************************************************************
2224 * FILEDLG95_SHELL_ExecuteCommand
2226 * Change the folder option and refresh the view
2227 * If the function succeeds, the return value is nonzero.
2229 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2231 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2233 IContextMenu * pcm;
2234 TRACE("(%p,%p)\n", hwnd, lpVerb);
2236 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2237 SVGIO_BACKGROUND,
2238 &IID_IContextMenu,
2239 (LPVOID*)&pcm)))
2241 CMINVOKECOMMANDINFO ci;
2242 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2243 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2244 ci.lpVerb = lpVerb;
2245 ci.hwnd = hwnd;
2247 IContextMenu_InvokeCommand(pcm, &ci);
2248 IContextMenu_Release(pcm);
2251 return FALSE;
2254 /***********************************************************************
2255 * FILEDLG95_SHELL_UpFolder
2257 * Browse to the specified object
2258 * If the function succeeds, the return value is nonzero.
2260 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2262 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2264 TRACE("\n");
2266 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2267 NULL,
2268 SBSP_PARENT)))
2270 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2271 return TRUE;
2273 return FALSE;
2276 /***********************************************************************
2277 * FILEDLG95_SHELL_BrowseToDesktop
2279 * Browse to the Desktop
2280 * If the function succeeds, the return value is nonzero.
2282 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2284 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2285 LPITEMIDLIST pidl;
2286 HRESULT hres;
2288 TRACE("\n");
2290 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2291 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2292 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2293 COMDLG32_SHFree(pidl);
2294 return SUCCEEDED(hres);
2296 /***********************************************************************
2297 * FILEDLG95_SHELL_Clean
2299 * Cleans the memory used by shell objects
2301 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2303 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2305 TRACE("\n");
2307 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2309 /* clean Shell interfaces */
2310 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2311 IShellView_Release(fodInfos->Shell.FOIShellView);
2312 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2313 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2314 if (fodInfos->Shell.FOIDataObject)
2315 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2318 /***********************************************************************
2319 * FILEDLG95_FILETYPE_Init
2321 * Initialisation of the file type combo box
2323 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2325 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2326 int nFilters = 0; /* number of filters */
2327 int nFilterIndexCB;
2329 TRACE("\n");
2331 if(fodInfos->customfilter)
2333 /* customfilter has one entry... title\0ext\0
2334 * Set first entry of combo box item with customfilter
2336 LPWSTR lpstrExt;
2337 LPCWSTR lpstrPos = fodInfos->customfilter;
2339 /* Get the title */
2340 lpstrPos += strlenW(fodInfos->customfilter) + 1;
2342 /* Copy the extensions */
2343 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2344 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2345 strcpyW(lpstrExt,lpstrPos);
2347 /* Add the item at the end of the combo */
2348 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2349 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2350 nFilters++;
2352 if(fodInfos->filter)
2354 LPCWSTR lpstrPos = fodInfos->filter;
2356 for(;;)
2358 /* filter is a list... title\0ext\0......\0\0
2359 * Set the combo item text to the title and the item data
2360 * to the ext
2362 LPCWSTR lpstrDisplay;
2363 LPWSTR lpstrExt;
2365 /* Get the title */
2366 if(! *lpstrPos) break; /* end */
2367 lpstrDisplay = lpstrPos;
2368 lpstrPos += strlenW(lpstrPos) + 1;
2370 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2372 nFilters++;
2373 /* malformed filters are added anyway... */
2374 if (!*lpstrPos) break;
2376 /* Copy the extensions */
2377 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2378 strcpyW(lpstrExt,lpstrPos);
2379 lpstrPos += strlenW(lpstrPos) + 1;
2381 /* Add the item at the end of the combo */
2382 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2387 * Set the current filter to the one specified
2388 * in the initialisation structure
2390 if (fodInfos->filter || fodInfos->customfilter)
2392 LPWSTR lpstrFilter;
2394 /* Check to make sure our index isn't out of bounds. */
2395 if ( fodInfos->ofnInfos->nFilterIndex >
2396 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2397 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2399 /* set default filter index */
2400 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2401 fodInfos->ofnInfos->nFilterIndex = 1;
2403 /* calculate index of Combo Box item */
2404 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2405 if (fodInfos->customfilter == NULL)
2406 nFilterIndexCB--;
2408 /* Set the current index selection. */
2409 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2411 /* Get the corresponding text string from the combo box. */
2412 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2413 nFilterIndexCB);
2415 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2416 lpstrFilter = NULL;
2418 if(lpstrFilter)
2420 DWORD len;
2421 CharLowerW(lpstrFilter); /* lowercase */
2422 len = strlenW(lpstrFilter)+1;
2423 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2424 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2426 } else
2427 fodInfos->ofnInfos->nFilterIndex = 0;
2428 return S_OK;
2431 /***********************************************************************
2432 * FILEDLG95_FILETYPE_OnCommand
2434 * WM_COMMAND of the file type combo box
2435 * If the function succeeds, the return value is nonzero.
2437 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2439 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2441 switch(wNotifyCode)
2443 case CBN_SELENDOK:
2445 LPWSTR lpstrFilter;
2447 /* Get the current item of the filetype combo box */
2448 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2450 /* set the current filter index */
2451 fodInfos->ofnInfos->nFilterIndex = iItem +
2452 (fodInfos->customfilter == NULL ? 1 : 0);
2454 /* Set the current filter with the current selection */
2455 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2456 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2458 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2459 iItem);
2460 if((INT_PTR)lpstrFilter != CB_ERR)
2462 DWORD len;
2463 CharLowerW(lpstrFilter); /* lowercase */
2464 len = strlenW(lpstrFilter)+1;
2465 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2466 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2467 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2470 /* Refresh the actual view to display the included items*/
2471 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2474 return FALSE;
2476 /***********************************************************************
2477 * FILEDLG95_FILETYPE_SearchExt
2479 * searches for an extension in the filetype box
2481 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2483 int i, iCount = CBGetCount(hwnd);
2485 TRACE("%s\n", debugstr_w(lpstrExt));
2487 if(iCount != CB_ERR)
2489 for(i=0;i<iCount;i++)
2491 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2492 return i;
2495 return -1;
2498 /***********************************************************************
2499 * FILEDLG95_FILETYPE_Clean
2501 * Clean the memory used by the filetype combo box
2503 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2505 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2506 int iPos;
2507 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2509 TRACE("\n");
2511 /* Delete each string of the combo and their associated data */
2512 if(iCount != CB_ERR)
2514 for(iPos = iCount-1;iPos>=0;iPos--)
2516 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2517 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2520 /* Current filter */
2521 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2522 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2526 /***********************************************************************
2527 * FILEDLG95_LOOKIN_Init
2529 * Initialisation of the look in combo box
2532 /* Small helper function, to determine if the unixfs shell extension is rooted
2533 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2535 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2536 HKEY hKey;
2537 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2538 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2539 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2540 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2541 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2542 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2543 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2545 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2546 return FALSE;
2548 RegCloseKey(hKey);
2549 return TRUE;
2552 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2554 IShellFolder *psfRoot, *psfDrives;
2555 IEnumIDList *lpeRoot, *lpeDrives;
2556 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2558 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2560 TRACE("\n");
2562 liInfos->iMaxIndentation = 0;
2564 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2566 /* set item height for both text field and listbox */
2567 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2568 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2570 /* Turn on the extended UI for the combo box like Windows does */
2571 CBSetExtendedUI(hwndCombo, TRUE);
2573 /* Initialise data of Desktop folder */
2574 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2575 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2576 COMDLG32_SHFree(pidlTmp);
2578 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2580 SHGetDesktopFolder(&psfRoot);
2582 if (psfRoot)
2584 /* enumerate the contents of the desktop */
2585 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2587 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2589 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2591 /* If the unixfs extension is rooted, we don't expand the drives by default */
2592 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2594 /* special handling for CSIDL_DRIVES */
2595 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2597 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2599 /* enumerate the drives */
2600 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2602 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2604 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2605 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2606 COMDLG32_SHFree(pidlAbsTmp);
2607 COMDLG32_SHFree(pidlTmp1);
2609 IEnumIDList_Release(lpeDrives);
2611 IShellFolder_Release(psfDrives);
2616 COMDLG32_SHFree(pidlTmp);
2618 IEnumIDList_Release(lpeRoot);
2620 IShellFolder_Release(psfRoot);
2623 COMDLG32_SHFree(pidlDrives);
2626 /***********************************************************************
2627 * FILEDLG95_LOOKIN_DrawItem
2629 * WM_DRAWITEM message handler
2631 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2633 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2634 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2635 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2636 RECT rectText;
2637 RECT rectIcon;
2638 SHFILEINFOA sfi;
2639 HIMAGELIST ilItemImage;
2640 int iIndentation;
2641 TEXTMETRICA tm;
2642 LPSFOLDER tmpFolder;
2645 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2647 TRACE("\n");
2649 if(pDIStruct->itemID == -1)
2650 return 0;
2652 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2653 pDIStruct->itemID)))
2654 return 0;
2657 if(pDIStruct->itemID == liInfos->uSelectedItem)
2659 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2661 &sfi,
2662 sizeof (SHFILEINFOA),
2663 SHGFI_PIDL | SHGFI_SMALLICON |
2664 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2665 SHGFI_DISPLAYNAME );
2667 else
2669 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2671 &sfi,
2672 sizeof (SHFILEINFOA),
2673 SHGFI_PIDL | SHGFI_SMALLICON |
2674 SHGFI_SYSICONINDEX |
2675 SHGFI_DISPLAYNAME);
2678 /* Is this item selected ? */
2679 if(pDIStruct->itemState & ODS_SELECTED)
2681 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2682 SetBkColor(pDIStruct->hDC,crHighLight);
2683 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2685 else
2687 SetTextColor(pDIStruct->hDC,crText);
2688 SetBkColor(pDIStruct->hDC,crWin);
2689 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2692 /* Do not indent item if drawing in the edit of the combo */
2693 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2695 iIndentation = 0;
2696 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2698 &sfi,
2699 sizeof (SHFILEINFOA),
2700 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2701 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2704 else
2706 iIndentation = tmpFolder->m_iIndent;
2708 /* Draw text and icon */
2710 /* Initialise the icon display area */
2711 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2712 rectIcon.top = pDIStruct->rcItem.top;
2713 rectIcon.right = rectIcon.left + ICONWIDTH;
2714 rectIcon.bottom = pDIStruct->rcItem.bottom;
2716 /* Initialise the text display area */
2717 GetTextMetricsA(pDIStruct->hDC, &tm);
2718 rectText.left = rectIcon.right;
2719 rectText.top =
2720 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2721 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2722 rectText.bottom =
2723 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2725 /* Draw the icon from the image list */
2726 ImageList_Draw(ilItemImage,
2727 sfi.iIcon,
2728 pDIStruct->hDC,
2729 rectIcon.left,
2730 rectIcon.top,
2731 ILD_TRANSPARENT );
2733 /* Draw the associated text */
2734 if(sfi.szDisplayName)
2735 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2738 return NOERROR;
2741 /***********************************************************************
2742 * FILEDLG95_LOOKIN_OnCommand
2744 * LookIn combo box WM_COMMAND message handler
2745 * If the function succeeds, the return value is nonzero.
2747 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2749 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2751 TRACE("%p\n", fodInfos);
2753 switch(wNotifyCode)
2755 case CBN_SELENDOK:
2757 LPSFOLDER tmpFolder;
2758 int iItem;
2760 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2762 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2763 iItem)))
2764 return FALSE;
2767 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2768 tmpFolder->pidlItem,
2769 SBSP_ABSOLUTE)))
2771 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2772 return TRUE;
2774 break;
2778 return FALSE;
2781 /***********************************************************************
2782 * FILEDLG95_LOOKIN_AddItem
2784 * Adds an absolute pidl item to the lookin combo box
2785 * returns the index of the inserted item
2787 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2789 LPITEMIDLIST pidlNext;
2790 SHFILEINFOA sfi;
2791 SFOLDER *tmpFolder;
2792 LookInInfos *liInfos;
2794 TRACE("%08x\n", iInsertId);
2796 if(!pidl)
2797 return -1;
2799 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2800 return -1;
2802 tmpFolder = MemAlloc(sizeof(SFOLDER));
2803 tmpFolder->m_iIndent = 0;
2805 /* Calculate the indentation of the item in the lookin*/
2806 pidlNext = pidl;
2807 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2809 tmpFolder->m_iIndent++;
2812 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2814 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2815 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2817 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2818 SHGetFileInfoA((LPSTR)pidl,
2820 &sfi,
2821 sizeof(sfi),
2822 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2823 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2825 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2827 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2829 int iItemID;
2831 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2833 /* Add the item at the end of the list */
2834 if(iInsertId < 0)
2836 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2838 /* Insert the item at the iInsertId position*/
2839 else
2841 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2844 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2845 return iItemID;
2848 COMDLG32_SHFree( tmpFolder->pidlItem );
2849 MemFree( tmpFolder );
2850 return -1;
2854 /***********************************************************************
2855 * FILEDLG95_LOOKIN_InsertItemAfterParent
2857 * Insert an item below its parent
2859 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2862 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2863 int iParentPos;
2865 TRACE("\n");
2867 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2869 if(iParentPos < 0)
2871 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2874 /* Free pidlParent memory */
2875 COMDLG32_SHFree((LPVOID)pidlParent);
2877 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2880 /***********************************************************************
2881 * FILEDLG95_LOOKIN_SelectItem
2883 * Adds an absolute pidl item to the lookin combo box
2884 * returns the index of the inserted item
2886 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2888 int iItemPos;
2889 LookInInfos *liInfos;
2891 TRACE("\n");
2893 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2895 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2897 if(iItemPos < 0)
2899 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2900 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2903 else
2905 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2906 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2908 int iRemovedItem;
2910 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2911 break;
2912 if(iRemovedItem < iItemPos)
2913 iItemPos--;
2917 CBSetCurSel(hwnd,iItemPos);
2918 liInfos->uSelectedItem = iItemPos;
2920 return 0;
2924 /***********************************************************************
2925 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2927 * Remove the item with an expansion level over iExpansionLevel
2929 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2931 int iItemPos;
2933 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2935 TRACE("\n");
2937 if(liInfos->iMaxIndentation <= 2)
2938 return -1;
2940 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2942 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2943 COMDLG32_SHFree(tmpFolder->pidlItem);
2944 MemFree(tmpFolder);
2945 CBDeleteString(hwnd,iItemPos);
2946 liInfos->iMaxIndentation--;
2948 return iItemPos;
2951 return -1;
2954 /***********************************************************************
2955 * FILEDLG95_LOOKIN_SearchItem
2957 * Search for pidl in the lookin combo box
2958 * returns the index of the found item
2960 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2962 int i = 0;
2963 int iCount = CBGetCount(hwnd);
2965 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2967 if (iCount != CB_ERR)
2969 for(;i<iCount;i++)
2971 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2973 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2974 return i;
2975 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2976 return i;
2980 return -1;
2983 /***********************************************************************
2984 * FILEDLG95_LOOKIN_Clean
2986 * Clean the memory used by the lookin combo box
2988 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2990 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2991 int iPos;
2992 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2994 TRACE("\n");
2996 /* Delete each string of the combo and their associated data */
2997 if (iCount != CB_ERR)
2999 for(iPos = iCount-1;iPos>=0;iPos--)
3001 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3002 COMDLG32_SHFree(tmpFolder->pidlItem);
3003 MemFree(tmpFolder);
3004 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3008 /* LookInInfos structure */
3009 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3012 /***********************************************************************
3013 * FILEDLG95_FILENAME_FillFromSelection
3015 * fills the edit box from the cached DataObject
3017 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3019 FileOpenDlgInfos *fodInfos;
3020 LPITEMIDLIST pidl;
3021 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3022 char lpstrTemp[MAX_PATH];
3023 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
3025 TRACE("\n");
3026 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3028 /* Count how many files we have */
3029 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3031 /* calculate the string length, count files */
3032 if (nFileSelected >= 1)
3034 nLength += 3; /* first and last quotes, trailing \0 */
3035 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3037 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3039 if (pidl)
3041 /* get the total length of the selected file names */
3042 lpstrTemp[0] = '\0';
3043 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3045 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3047 nLength += strlen( lpstrTemp ) + 3;
3048 nFiles++;
3050 COMDLG32_SHFree( pidl );
3055 /* allocate the buffer */
3056 if (nFiles <= 1) nLength = MAX_PATH;
3057 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
3058 lpstrAllFile[0] = '\0';
3060 /* Generate the string for the edit control */
3061 if(nFiles >= 1)
3063 lpstrCurrFile = lpstrAllFile;
3064 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3066 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3068 if (pidl)
3070 /* get the file name */
3071 lpstrTemp[0] = '\0';
3072 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3074 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3076 if ( nFiles > 1)
3078 *lpstrCurrFile++ = '\"';
3079 strcpy( lpstrCurrFile, lpstrTemp );
3080 lpstrCurrFile += strlen( lpstrTemp );
3081 strcpy( lpstrCurrFile, "\" " );
3082 lpstrCurrFile += 2;
3084 else
3086 strcpy( lpstrAllFile, lpstrTemp );
3089 COMDLG32_SHFree( (LPVOID) pidl );
3092 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3094 /* Select the file name like Windows does */
3095 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
3097 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3101 /* copied from shell32 to avoid linking to it
3102 * FIXME: why? shell32 is already linked
3104 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3106 switch (src->uType)
3108 case STRRET_WSTR:
3109 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
3110 COMDLG32_SHFree(src->u.pOleStr);
3111 break;
3113 case STRRET_CSTR:
3114 lstrcpynA((LPSTR)dest, src->u.cStr, len);
3115 break;
3117 case STRRET_OFFSET:
3118 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
3119 break;
3121 default:
3122 FIXME("unknown type!\n");
3123 if (len)
3125 *(LPSTR)dest = '\0';
3127 return(E_FAIL);
3129 return S_OK;
3132 /***********************************************************************
3133 * FILEDLG95_FILENAME_GetFileNames
3135 * Copies the filenames to a delimited string list.
3136 * The delimiter is specified by the parameter 'separator',
3137 * usually either a space or a nul
3139 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3141 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3142 UINT nStrCharCount = 0; /* index in src buffer */
3143 UINT nFileIndex = 0; /* index in dest buffer */
3144 UINT nFileCount = 0; /* number of files */
3145 UINT nStrLen = 0; /* length of string in edit control */
3146 LPWSTR lpstrEdit; /* buffer for string from edit control */
3148 TRACE("\n");
3150 /* get the filenames from the edit control */
3151 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3152 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3153 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3155 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3157 /* we might get single filename without any '"',
3158 * so we need nStrLen + terminating \0 + end-of-list \0 */
3159 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3160 *sizeUsed = 0;
3162 /* build delimited file list from filenames */
3163 while ( nStrCharCount <= nStrLen )
3165 if ( lpstrEdit[nStrCharCount]=='"' )
3167 nStrCharCount++;
3168 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3170 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3171 (*sizeUsed)++;
3172 nStrCharCount++;
3174 (*lpstrFileList)[nFileIndex++] = separator;
3175 (*sizeUsed)++;
3176 nFileCount++;
3178 nStrCharCount++;
3181 /* single, unquoted string */
3182 if ((nStrLen > 0) && (*sizeUsed == 0) )
3184 strcpyW(*lpstrFileList, lpstrEdit);
3185 nFileIndex = strlenW(lpstrEdit) + 1;
3186 (*sizeUsed) = nFileIndex;
3187 nFileCount = 1;
3190 /* trailing \0 */
3191 (*lpstrFileList)[nFileIndex] = '\0';
3192 (*sizeUsed)++;
3194 MemFree(lpstrEdit);
3195 return nFileCount;
3198 #define SETDefFormatEtc(fe,cf,med) \
3200 (fe).cfFormat = cf;\
3201 (fe).dwAspect = DVASPECT_CONTENT; \
3202 (fe).ptd =NULL;\
3203 (fe).tymed = med;\
3204 (fe).lindex = -1;\
3208 * DATAOBJECT Helper functions
3211 /***********************************************************************
3212 * COMCTL32_ReleaseStgMedium
3214 * like ReleaseStgMedium from ole32
3216 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3218 if(medium.pUnkForRelease)
3220 IUnknown_Release(medium.pUnkForRelease);
3222 else
3224 GlobalUnlock(medium.u.hGlobal);
3225 GlobalFree(medium.u.hGlobal);
3229 /***********************************************************************
3230 * GetPidlFromDataObject
3232 * Return pidl(s) by number from the cached DataObject
3234 * nPidlIndex=0 gets the fully qualified root path
3236 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3239 STGMEDIUM medium;
3240 FORMATETC formatetc;
3241 LPITEMIDLIST pidl = NULL;
3243 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3245 if (!doSelected)
3246 return NULL;
3248 /* Set the FORMATETC structure*/
3249 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3251 /* Get the pidls from IDataObject */
3252 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3254 LPIDA cida = GlobalLock(medium.u.hGlobal);
3255 if(nPidlIndex <= cida->cidl)
3257 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3259 COMCTL32_ReleaseStgMedium(medium);
3261 return pidl;
3264 /***********************************************************************
3265 * GetNumSelected
3267 * Return the number of selected items in the DataObject.
3270 UINT GetNumSelected( IDataObject *doSelected )
3272 UINT retVal = 0;
3273 STGMEDIUM medium;
3274 FORMATETC formatetc;
3276 TRACE("sv=%p\n", doSelected);
3278 if (!doSelected) return 0;
3280 /* Set the FORMATETC structure*/
3281 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3283 /* Get the pidls from IDataObject */
3284 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3286 LPIDA cida = GlobalLock(medium.u.hGlobal);
3287 retVal = cida->cidl;
3288 COMCTL32_ReleaseStgMedium(medium);
3289 return retVal;
3291 return 0;
3295 * TOOLS
3298 /***********************************************************************
3299 * GetName
3301 * Get the pidl's display name (relative to folder) and
3302 * put it in lpstrFileName.
3304 * Return NOERROR on success,
3305 * E_FAIL otherwise
3308 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3310 STRRET str;
3311 HRESULT hRes;
3313 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3315 if(!lpsf)
3317 SHGetDesktopFolder(&lpsf);
3318 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3319 IShellFolder_Release(lpsf);
3320 return hRes;
3323 /* Get the display name of the pidl relative to the folder */
3324 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3326 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3328 return E_FAIL;
3331 /***********************************************************************
3332 * GetShellFolderFromPidl
3334 * pidlRel is the item pidl relative
3335 * Return the IShellFolder of the absolute pidl
3337 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3339 IShellFolder *psf = NULL,*psfParent;
3341 TRACE("%p\n", pidlAbs);
3343 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3345 psf = psfParent;
3346 if(pidlAbs && pidlAbs->mkid.cb)
3348 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3350 IShellFolder_Release(psfParent);
3351 return psf;
3354 /* return the desktop */
3355 return psfParent;
3357 return NULL;
3360 /***********************************************************************
3361 * GetParentPidl
3363 * Return the LPITEMIDLIST to the parent of the pidl in the list
3365 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3367 LPITEMIDLIST pidlParent;
3369 TRACE("%p\n", pidl);
3371 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3372 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3374 return pidlParent;
3377 /***********************************************************************
3378 * GetPidlFromName
3380 * returns the pidl of the file name relative to folder
3381 * NULL if an error occurred
3383 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3385 LPITEMIDLIST pidl = NULL;
3386 ULONG ulEaten;
3388 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3390 if(!lpcstrFileName) return NULL;
3391 if(!*lpcstrFileName) return NULL;
3393 if(!lpsf)
3395 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3396 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3397 IShellFolder_Release(lpsf);
3400 else
3402 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3404 return pidl;
3409 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3411 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3412 HRESULT ret;
3414 TRACE("%p, %p\n", psf, pidl);
3416 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3418 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3419 /* see documentation shell 4.1*/
3420 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3423 /***********************************************************************
3424 * BrowseSelectedFolder
3426 static BOOL BrowseSelectedFolder(HWND hwnd)
3428 BOOL bBrowseSelFolder = FALSE;
3429 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3431 TRACE("\n");
3433 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3435 LPITEMIDLIST pidlSelection;
3437 /* get the file selected */
3438 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3439 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3441 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3442 pidlSelection, SBSP_RELATIVE ) ) )
3444 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3445 ' ','n','o','t',' ','e','x','i','s','t',0};
3446 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3448 bBrowseSelFolder = TRUE;
3449 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3451 COMDLG32_SHFree( pidlSelection );
3454 return bBrowseSelFolder;
3458 * Memory allocation methods */
3459 static void *MemAlloc(UINT size)
3461 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3464 static void MemFree(void *mem)
3466 HeapFree(GetProcessHeap(),0,mem);
3470 * Old-style (win3.1) dialogs */
3472 /***********************************************************************
3473 * FD32_GetTemplate [internal]
3475 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3476 * by a 32 bits application
3479 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3481 LPOPENFILENAMEW ofnW = lfs->ofnW;
3482 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3483 HANDLE hDlgTmpl;
3485 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3487 if (!(lfs->template = LockResource( ofnW->hInstance )))
3489 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3490 return FALSE;
3493 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3495 HRSRC hResInfo;
3496 if (priv->ofnA)
3497 hResInfo = FindResourceA(priv->ofnA->hInstance,
3498 priv->ofnA->lpTemplateName,
3499 (LPSTR)RT_DIALOG);
3500 else
3501 hResInfo = FindResourceW(ofnW->hInstance,
3502 ofnW->lpTemplateName,
3503 (LPWSTR)RT_DIALOG);
3504 if (!hResInfo)
3506 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3507 return FALSE;
3509 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3510 hResInfo)) ||
3511 !(lfs->template = LockResource(hDlgTmpl)))
3513 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3514 return FALSE;
3516 } else { /* get it from internal Wine resource */
3517 HRSRC hResInfo;
3518 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3519 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3521 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3522 return FALSE;
3524 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3525 !(lfs->template = LockResource( hDlgTmpl )))
3527 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3528 return FALSE;
3531 return TRUE;
3535 /************************************************************************
3536 * FD32_Init [internal]
3537 * called from the common 16/32 code to initialize 32 bit data
3539 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3541 BOOL IsUnicode = (BOOL) data;
3542 PFD32_PRIVATE priv;
3544 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3545 lfs->private1632 = priv;
3546 if (NULL == lfs->private1632) return FALSE;
3547 if (IsUnicode)
3549 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3550 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3551 if (lfs->ofnW->lpfnHook)
3552 lfs->hook = TRUE;
3554 else
3556 priv->ofnA = (LPOPENFILENAMEA) lParam;
3557 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3558 if (priv->ofnA->lpfnHook)
3559 lfs->hook = TRUE;
3560 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3561 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3564 if (! FD32_GetTemplate(lfs)) return FALSE;
3566 return TRUE;
3569 /***********************************************************************
3570 * FD32_CallWindowProc [internal]
3572 * called from the common 16/32 code to call the appropriate hook
3574 static BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
3575 LPARAM lParam)
3577 BOOL ret;
3578 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3580 if (priv->ofnA)
3582 TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3583 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3584 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3585 TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3586 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3587 return ret;
3590 TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3591 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3592 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3593 TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3594 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3595 return ret;
3598 /***********************************************************************
3599 * FD32_UpdateResult [internal]
3600 * update the real client structures if any
3602 static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs)
3604 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3605 LPOPENFILENAMEW ofnW = lfs->ofnW;
3607 if (priv->ofnA)
3609 if (ofnW->nMaxFile &&
3610 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3611 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3612 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3613 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3614 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3618 /***********************************************************************
3619 * FD32_UpdateFileTitle [internal]
3620 * update the real client structures if any
3622 static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs)
3624 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3625 LPOPENFILENAMEW ofnW = lfs->ofnW;
3627 if (priv->ofnA)
3629 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3630 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3631 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3636 /***********************************************************************
3637 * FD32_SendLbGetCurSel [internal]
3638 * retrieve selected listbox item
3640 static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs)
3642 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3646 /************************************************************************
3647 * FD32_Destroy [internal]
3648 * called from the common 16/32 code to cleanup 32 bit data
3650 static void CALLBACK FD32_Destroy(PFD31_DATA lfs)
3652 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3654 /* if ofnW has been allocated, have to free everything in it */
3655 if (NULL != priv && NULL != priv->ofnA)
3657 FD31_FreeOfnW(lfs->ofnW);
3658 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3662 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3664 callbacks->Init = FD32_Init;
3665 callbacks->CWP = FD32_CallWindowProc;
3666 callbacks->UpdateResult = FD32_UpdateResult;
3667 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3668 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3669 callbacks->Destroy = FD32_Destroy;
3672 /***********************************************************************
3673 * FD32_WMMeasureItem [internal]
3675 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3677 LPMEASUREITEMSTRUCT lpmeasure;
3679 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3680 lpmeasure->itemHeight = FD31_GetFldrHeight();
3681 return TRUE;
3685 /***********************************************************************
3686 * FileOpenDlgProc [internal]
3687 * Used for open and save, in fact.
3689 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3690 WPARAM wParam, LPARAM lParam)
3692 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3694 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
3695 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3697 INT_PTR lRet;
3698 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3699 if (lRet)
3700 return lRet; /* else continue message processing */
3702 switch (wMsg)
3704 case WM_INITDIALOG:
3705 return FD31_WMInitDialog(hWnd, wParam, lParam);
3707 case WM_MEASUREITEM:
3708 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3710 case WM_DRAWITEM:
3711 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3713 case WM_COMMAND:
3714 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3715 #if 0
3716 case WM_CTLCOLOR:
3717 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3718 switch (HIWORD(lParam))
3720 case CTLCOLOR_BTN:
3721 SetTextColor((HDC16)wParam, 0x00000000);
3722 return hGRAYBrush;
3723 case CTLCOLOR_STATIC:
3724 SetTextColor((HDC16)wParam, 0x00000000);
3725 return hGRAYBrush;
3727 break;
3728 #endif
3730 return FALSE;
3734 /***********************************************************************
3735 * GetFileName31A [internal]
3737 * Creates a win31 style dialog box for the user to select a file to open/save.
3739 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3740 UINT dlgType /* type dialogue : open/save */
3743 HINSTANCE hInst;
3744 BOOL bRet = FALSE;
3745 PFD31_DATA lfs;
3746 FD31_CALLBACKS callbacks;
3748 if (!lpofn || !FD31_Init()) return FALSE;
3750 TRACE("ofn flags %08lx\n", lpofn->Flags);
3751 FD32_SetupCallbacks(&callbacks);
3752 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3753 if (lfs)
3755 hInst = (HINSTANCE)GetWindowLongPtrA( lpofn->hwndOwner, GWLP_HINSTANCE );
3756 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3757 FD32_FileOpenDlgProc, (LPARAM)lfs);
3758 FD31_DestroyPrivate(lfs);
3761 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3762 return bRet;
3765 /***********************************************************************
3766 * GetFileName31W [internal]
3768 * Creates a win31 style dialog box for the user to select a file to open/save
3770 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3771 UINT dlgType /* type dialogue : open/save */
3774 HINSTANCE hInst;
3775 BOOL bRet = FALSE;
3776 PFD31_DATA lfs;
3777 FD31_CALLBACKS callbacks;
3779 if (!lpofn || !FD31_Init()) return FALSE;
3781 FD32_SetupCallbacks(&callbacks);
3782 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3783 if (lfs)
3785 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3786 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3787 FD32_FileOpenDlgProc, (LPARAM)lfs);
3788 FD31_DestroyPrivate(lfs);
3791 TRACE("file %s, file offset %d, ext offset %d\n",
3792 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3793 return bRet;
3796 /* ------------------ APIs ---------------------- */
3798 /***********************************************************************
3799 * GetOpenFileNameA (COMDLG32.@)
3801 * Creates a dialog box for the user to select a file to open.
3803 * RETURNS
3804 * TRUE on success: user enters a valid file
3805 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3808 BOOL WINAPI GetOpenFileNameA(
3809 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3811 BOOL win16look = FALSE;
3813 TRACE("flags %08lx\n", ofn->Flags);
3815 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3816 if (ofn->Flags & OFN_FILEMUSTEXIST)
3817 ofn->Flags |= OFN_PATHMUSTEXIST;
3819 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3820 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3822 if (win16look)
3823 return GetFileName31A(ofn, OPEN_DIALOG);
3824 else
3825 return GetFileDialog95A(ofn, OPEN_DIALOG);
3828 /***********************************************************************
3829 * GetOpenFileNameW (COMDLG32.@)
3831 * Creates a dialog box for the user to select a file to open.
3833 * RETURNS
3834 * TRUE on success: user enters a valid file
3835 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3838 BOOL WINAPI GetOpenFileNameW(
3839 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3841 BOOL win16look = FALSE;
3843 TRACE("flags %08lx\n", ofn->Flags);
3845 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3846 if (ofn->Flags & OFN_FILEMUSTEXIST)
3847 ofn->Flags |= OFN_PATHMUSTEXIST;
3849 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3850 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3852 if (win16look)
3853 return GetFileName31W(ofn, OPEN_DIALOG);
3854 else
3855 return GetFileDialog95W(ofn, OPEN_DIALOG);
3859 /***********************************************************************
3860 * GetSaveFileNameA (COMDLG32.@)
3862 * Creates a dialog box for the user to select a file to save.
3864 * RETURNS
3865 * TRUE on success: user enters a valid file
3866 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3869 BOOL WINAPI GetSaveFileNameA(
3870 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3872 BOOL win16look = FALSE;
3874 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3875 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3877 if (win16look)
3878 return GetFileName31A(ofn, SAVE_DIALOG);
3879 else
3880 return GetFileDialog95A(ofn, SAVE_DIALOG);
3883 /***********************************************************************
3884 * GetSaveFileNameW (COMDLG32.@)
3886 * Creates a dialog box for the user to select a file to save.
3888 * RETURNS
3889 * TRUE on success: user enters a valid file
3890 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3893 BOOL WINAPI GetSaveFileNameW(
3894 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3896 BOOL win16look = FALSE;
3898 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3899 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3901 if (win16look)
3902 return GetFileName31W(ofn, SAVE_DIALOG);
3903 else
3904 return GetFileDialog95W(ofn, SAVE_DIALOG);