Fixed memory leak introduced in previous change.
[wine/multimedia.git] / dlls / commdlg / filedlg.c
blob95b856fcb401ee8e5fd5bddfe9a0163da72628cf
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 void 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;
254 /* test for missing functionality */
255 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
257 FIXME("Flags 0x%08lx not yet implemented\n",
258 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
261 /* Create the dialog from a template */
263 if(!(hRes = FindResourceA(COMDLG32_hInstance,MAKEINTRESOURCEA(NEWFILEOPENORD),(LPSTR)RT_DIALOG)))
265 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
266 return FALSE;
268 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
269 !(template = LockResource( hDlgTmpl )))
271 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
272 return FALSE;
275 /* old style hook messages */
276 if (IsHooked(fodInfos))
278 fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
279 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
280 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
281 fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
284 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
285 (LPDLGTEMPLATEA) template,
286 fodInfos->ofnInfos->hwndOwner,
287 FileOpenDlgProc95,
288 (LPARAM) fodInfos);
290 /* Unable to create the dialog */
291 if( lRes == -1)
292 return FALSE;
294 return lRes;
297 /***********************************************************************
298 * GetFileDialog95A
300 * Call GetFileName95 with this structure and clean the memory.
302 * IN : The OPENFILENAMEA initialisation structure passed to
303 * GetOpenFileNameA win api function (see filedlg.c)
305 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
307 BOOL ret;
308 FileOpenDlgInfos fodInfos;
309 LPSTR lpstrSavDir = NULL;
310 LPWSTR title = NULL;
311 LPWSTR defext = NULL;
312 LPWSTR filter = NULL;
313 LPWSTR customfilter = NULL;
315 /* Initialize FileOpenDlgInfos structure */
316 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
318 /* Pass in the original ofn */
319 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
321 /* save current directory */
322 if (ofn->Flags & OFN_NOCHANGEDIR)
324 lpstrSavDir = MemAlloc(MAX_PATH);
325 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
328 fodInfos.unicode = FALSE;
330 /* convert all the input strings to unicode */
331 if(ofn->lpstrInitialDir)
333 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
334 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
335 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
337 else
338 fodInfos.initdir = NULL;
340 if(ofn->lpstrFile)
342 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
343 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
345 else
346 fodInfos.filename = NULL;
348 if(ofn->lpstrDefExt)
350 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
351 defext = MemAlloc((len+1)*sizeof(WCHAR));
352 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
354 fodInfos.defext = defext;
356 if(ofn->lpstrTitle)
358 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
359 title = MemAlloc((len+1)*sizeof(WCHAR));
360 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
362 fodInfos.title = title;
364 if (ofn->lpstrFilter)
366 LPCSTR s;
367 int n, len;
369 /* filter is a list... title\0ext\0......\0\0 */
370 s = ofn->lpstrFilter;
371 while (*s) s = s+strlen(s)+1;
372 s++;
373 n = s - ofn->lpstrFilter;
374 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
375 filter = MemAlloc(len*sizeof(WCHAR));
376 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
378 fodInfos.filter = filter;
380 /* convert lpstrCustomFilter */
381 if (ofn->lpstrCustomFilter)
383 LPCSTR s;
384 int n, len;
386 /* customfilter contains a pair of strings... title\0ext\0 */
387 s = ofn->lpstrCustomFilter;
388 if (*s) s = s+strlen(s)+1;
389 if (*s) s = s+strlen(s)+1;
390 n = s - ofn->lpstrCustomFilter;
391 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
392 customfilter = MemAlloc(len*sizeof(WCHAR));
393 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
395 fodInfos.customfilter = customfilter;
397 /* Initialize the dialog property */
398 fodInfos.DlgInfos.dwDlgProp = 0;
399 fodInfos.DlgInfos.hwndCustomDlg = NULL;
401 switch(iDlgType)
403 case OPEN_DIALOG :
404 ret = GetFileName95(&fodInfos);
405 break;
406 case SAVE_DIALOG :
407 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
408 ret = GetFileName95(&fodInfos);
409 break;
410 default :
411 ret = 0;
414 if (lpstrSavDir)
416 SetCurrentDirectoryA(lpstrSavDir);
417 MemFree(lpstrSavDir);
420 if(title)
421 MemFree(title);
422 if(defext)
423 MemFree(defext);
424 if(filter)
425 MemFree(filter);
426 if(customfilter)
427 MemFree(customfilter);
428 if(fodInfos.initdir)
429 MemFree(fodInfos.initdir);
431 if(fodInfos.filename)
432 MemFree(fodInfos.filename);
434 TRACE("selected file: %s\n",ofn->lpstrFile);
436 return ret;
439 /***********************************************************************
440 * GetFileDialog95W
442 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
443 * Call GetFileName95 with this structure and clean the memory.
446 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
448 BOOL ret;
449 FileOpenDlgInfos fodInfos;
450 LPWSTR lpstrSavDir = NULL;
452 /* Initialize FileOpenDlgInfos structure */
453 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
455 /* Pass in the original ofn */
456 fodInfos.ofnInfos = ofn;
458 fodInfos.title = ofn->lpstrTitle;
459 fodInfos.defext = ofn->lpstrDefExt;
460 fodInfos.filter = ofn->lpstrFilter;
461 fodInfos.customfilter = ofn->lpstrCustomFilter;
463 /* convert string arguments, save others */
464 if(ofn->lpstrFile)
466 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
467 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
469 else
470 fodInfos.filename = NULL;
472 if(ofn->lpstrInitialDir)
474 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
475 DWORD len = strlenW(ofn->lpstrInitialDir)+1;
476 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
477 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
479 else
480 fodInfos.initdir = NULL;
482 /* save current directory */
483 if (ofn->Flags & OFN_NOCHANGEDIR)
485 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
486 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
489 fodInfos.unicode = TRUE;
491 switch(iDlgType)
493 case OPEN_DIALOG :
494 ret = GetFileName95(&fodInfos);
495 break;
496 case SAVE_DIALOG :
497 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
498 ret = GetFileName95(&fodInfos);
499 break;
500 default :
501 ret = 0;
504 if (lpstrSavDir)
506 SetCurrentDirectoryW(lpstrSavDir);
507 MemFree(lpstrSavDir);
510 /* restore saved IN arguments and convert OUT arguments back */
511 MemFree(fodInfos.filename);
512 MemFree(fodInfos.initdir);
513 return ret;
516 /******************************************************************************
517 * COMDLG32_GetDisplayNameOf [internal]
519 * Helper function to get the display name for a pidl.
521 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
522 LPSHELLFOLDER psfDesktop;
523 STRRET strret;
525 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
526 return FALSE;
528 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
529 IShellFolder_Release(psfDesktop);
530 return FALSE;
533 IShellFolder_Release(psfDesktop);
534 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
537 /***********************************************************************
538 * ArrangeCtrlPositions [internal]
540 * NOTE: Do not change anything here without a lot of testing.
542 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
544 HWND hwndChild, hwndStc32;
545 RECT rectParent, rectChild, rectStc32;
546 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
548 /* Take into account if open as read only checkbox and help button
549 * are hidden
551 if (hide_help)
553 RECT rectHelp, rectCancel;
554 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
555 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
556 /* subtract the height of the help button plus the space between
557 * the help button and the cancel button to the height of the dialog
559 help_fixup = rectHelp.bottom - rectCancel.bottom;
563 There are two possibilities to add components to the default file dialog box.
565 By default, all the new components are added below the standard dialog box (the else case).
567 However, if there is a static text component with the stc32 id, a special case happens.
568 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
569 in the window and the cx and cy indicate how to size the window.
570 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
571 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
575 GetClientRect(hwndParentDlg, &rectParent);
577 /* when arranging controls we have to use fixed parent size */
578 rectParent.bottom -= help_fixup;
580 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
581 if (hwndStc32)
583 GetWindowRect(hwndStc32, &rectStc32);
584 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
586 /* set the size of the stc32 control according to the size of
587 * client area of the parent dialog
589 SetWindowPos(hwndStc32, 0,
590 0, 0,
591 rectParent.right, rectParent.bottom,
592 SWP_NOMOVE | SWP_NOZORDER);
594 else
595 SetRectEmpty(&rectStc32);
597 /* this part moves controls of the child dialog */
598 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
599 while (hwndChild)
601 if (hwndChild != hwndStc32)
603 GetWindowRect(hwndChild, &rectChild);
604 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
606 /* move only if stc32 exist */
607 if (hwndStc32 && rectChild.left > rectStc32.right)
609 LONG old_left = rectChild.left;
611 /* move to the right of visible controls of the parent dialog */
612 rectChild.left += rectParent.right;
613 rectChild.left -= rectStc32.right;
615 child_width_fixup = rectChild.left - old_left;
617 /* move even if stc32 doesn't exist */
618 if (rectChild.top >= rectStc32.bottom)
620 LONG old_top = rectChild.top;
622 /* move below visible controls of the parent dialog */
623 rectChild.top += rectParent.bottom;
624 rectChild.top -= rectStc32.bottom - rectStc32.top;
626 child_height_fixup = rectChild.top - old_top;
629 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
630 0, 0, SWP_NOSIZE | SWP_NOZORDER);
632 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
635 /* this part moves controls of the parent dialog */
636 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
637 while (hwndChild)
639 if (hwndChild != hwndChildDlg)
641 GetWindowRect(hwndChild, &rectChild);
642 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
644 /* left,top of stc32 marks the position of controls
645 * from the parent dialog
647 rectChild.left += rectStc32.left;
648 rectChild.top += rectStc32.top;
650 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
651 0, 0, SWP_NOSIZE | SWP_NOZORDER);
653 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
656 /* calculate the size of the resulting dialog */
658 /* here we have to use original parent size */
659 GetClientRect(hwndParentDlg, &rectParent);
660 GetClientRect(hwndChildDlg, &rectChild);
662 if (hwndStc32)
664 rectChild.right += child_width_fixup;
665 rectChild.bottom += child_height_fixup;
667 if (rectParent.right > rectChild.right)
669 rectParent.right += rectChild.right;
670 rectParent.right -= rectStc32.right - rectStc32.left;
672 else
674 rectParent.right = rectChild.right;
677 if (rectParent.bottom > rectChild.bottom)
679 rectParent.bottom += rectChild.bottom;
680 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
682 else
684 /* child dialog is higher, unconditionally set new dialog
685 * height to its size (help_fixup will be subtracted below)
687 rectParent.bottom = rectChild.bottom + help_fixup;
690 else
692 rectParent.bottom += rectChild.bottom;
695 /* finally use fixed parent size */
696 rectParent.bottom -= help_fixup;
698 /* save the size of the parent's client area */
699 rectChild.right = rectParent.right;
700 rectChild.bottom = rectParent.bottom;
702 /* set the size of the parent dialog */
703 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
704 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
705 SetWindowPos(hwndParentDlg, 0,
706 0, 0,
707 rectParent.right - rectParent.left,
708 rectParent.bottom - rectParent.top,
709 SWP_NOMOVE | SWP_NOZORDER);
711 /* set the size of the child dialog */
712 SetWindowPos(hwndChildDlg, HWND_BOTTOM,
713 0, 0, rectChild.right, rectChild.bottom, SWP_NOACTIVATE);
716 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
718 switch(uMsg) {
719 case WM_INITDIALOG:
720 return TRUE;
722 return FALSE;
725 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
727 LPCVOID template;
728 HRSRC hRes;
729 HANDLE hDlgTmpl = 0;
730 HWND hChildDlg = 0;
732 TRACE("\n");
735 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
736 * structure's hInstance parameter is not a HINSTANCE, but
737 * instead a pointer to a template resource to use.
739 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
741 HINSTANCE hinst;
742 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
744 hinst = 0;
745 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
747 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
748 return NULL;
751 else
753 hinst = fodInfos->ofnInfos->hInstance;
754 if(fodInfos->unicode)
756 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
757 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
759 else
761 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
762 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
764 if (!hRes)
766 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
767 return NULL;
769 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
770 !(template = LockResource( hDlgTmpl )))
772 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
773 return NULL;
776 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, template, hwnd,
777 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
778 (LPARAM)fodInfos->ofnInfos);
779 if(hChildDlg)
781 ShowWindow(hChildDlg,SW_SHOW);
782 return hChildDlg;
785 else if( IsHooked(fodInfos))
787 RECT rectHwnd;
788 struct {
789 DLGTEMPLATE tmplate;
790 WORD menu,class,title;
791 } temp;
792 GetClientRect(hwnd,&rectHwnd);
793 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
794 temp.tmplate.dwExtendedStyle = 0;
795 temp.tmplate.cdit = 0;
796 temp.tmplate.x = 0;
797 temp.tmplate.y = 0;
798 temp.tmplate.cx = 0;
799 temp.tmplate.cy = 0;
800 temp.menu = temp.class = temp.title = 0;
802 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
803 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
805 return hChildDlg;
807 return NULL;
810 /***********************************************************************
811 * SendCustomDlgNotificationMessage
813 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
816 void SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
818 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
820 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
822 if(!fodInfos) return;
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 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 SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
847 TRACE("RET NOTIFY\n");
851 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer)
853 UINT sizeUsed = 0, n, total;
854 LPWSTR lpstrFileList = NULL;
855 WCHAR lpstrCurrentDir[MAX_PATH];
856 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
858 TRACE("CDM_GETFILEPATH:\n");
860 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
861 return -1;
863 /* get path and filenames */
864 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrCurrentDir);
865 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
867 TRACE("path >%s< filespec >%s< %d files\n",
868 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
870 if( fodInfos->unicode )
872 LPWSTR bufW = buffer;
873 total = strlenW(lpstrCurrentDir) + 1 + sizeUsed;
875 /* Prepend the current path */
876 n = strlenW(lpstrCurrentDir) + 1;
877 memcpy( bufW, lpstrCurrentDir, min(n,size) * sizeof(WCHAR));
878 if(n<size)
880 /* 'n' includes trailing \0 */
881 bufW[n-1] = '\\';
882 memcpy( &bufW[n], lpstrFileList, (size-n)*sizeof(WCHAR) );
884 TRACE("returned -> %s\n",debugstr_wn(bufW, total));
886 else
888 LPSTR bufA = buffer;
889 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
890 NULL, 0, NULL, NULL);
891 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
892 NULL, 0, NULL, NULL);
894 /* Prepend the current path */
895 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
896 bufA, size, NULL, NULL);
898 if(n<size)
900 /* 'n' includes trailing \0 */
901 bufA[n-1] = '\\';
902 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
903 &bufA[n], size-n, NULL, NULL);
906 TRACE("returned -> %s\n",debugstr_an(bufA, total));
908 MemFree(lpstrFileList);
910 return total;
913 static INT_PTR FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer)
915 UINT sizeUsed = 0;
916 LPWSTR lpstrFileList = NULL;
917 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
919 TRACE("CDM_GETSPEC:\n");
921 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
922 if( fodInfos->unicode )
924 LPWSTR bufW = buffer;
925 memcpy( bufW, lpstrFileList, sizeof(WCHAR)*sizeUsed );
927 else
929 LPSTR bufA = buffer;
930 sizeUsed = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed,
931 NULL, 0, NULL, NULL);
932 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
933 bufA, size, NULL, NULL);
935 MemFree(lpstrFileList);
937 return sizeUsed;
940 /***********************************************************************
941 * FILEDLG95_HandleCustomDialogMessages
943 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
945 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
947 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
948 WCHAR lpstrPath[MAX_PATH];
949 INT_PTR retval;
951 if(!fodInfos) return FALSE;
953 switch(uMsg)
955 case CDM_GETFILEPATH:
956 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
957 break;
959 case CDM_GETFOLDERPATH:
960 TRACE("CDM_GETFOLDERPATH:\n");
961 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
962 if (lParam)
964 if (fodInfos->unicode)
965 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
966 else
967 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
968 (LPSTR)lParam, (int)wParam, NULL, NULL);
970 retval = strlenW(lpstrPath);
971 break;
973 case CDM_GETSPEC:
974 retval = FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
975 break;
977 case CDM_SETCONTROLTEXT:
978 TRACE("CDM_SETCONTROLTEXT:\n");
979 if ( lParam )
981 if( fodInfos->unicode )
982 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
983 else
984 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
986 retval = TRUE;
987 break;
989 case CDM_HIDECONTROL:
990 case CDM_SETDEFEXT:
991 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
992 retval = -1;
993 break;
995 default:
996 return FALSE;
998 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
999 return TRUE;
1002 /***********************************************************************
1003 * FileOpenDlgProc95
1005 * File open dialog procedure
1007 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1009 #if 0
1010 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
1011 #endif
1013 switch(uMsg)
1015 case WM_INITDIALOG:
1017 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1019 /* Adds the FileOpenDlgInfos in the property list of the dialog
1020 so it will be easily accessible through a GetPropA(...) */
1021 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
1023 fodInfos->DlgInfos.hwndCustomDlg =
1024 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1026 FILEDLG95_InitControls(hwnd);
1028 if (fodInfos->DlgInfos.hwndCustomDlg)
1029 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1030 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1032 FILEDLG95_FillControls(hwnd, wParam, lParam);
1034 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1035 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1036 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1037 return 0;
1039 case WM_COMMAND:
1040 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1041 case WM_DRAWITEM:
1043 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1045 case IDC_LOOKIN:
1046 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1047 return TRUE;
1050 return FALSE;
1052 case WM_GETISHELLBROWSER:
1053 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1055 case WM_DESTROY:
1056 RemovePropA(hwnd, FileOpenDlgInfosStr);
1057 return FALSE;
1059 case WM_NOTIFY:
1061 LPNMHDR lpnmh = (LPNMHDR)lParam;
1062 UINT stringId = -1;
1064 /* set up the button tooltips strings */
1065 if(TTN_GETDISPINFOA == lpnmh->code )
1067 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1068 switch(lpnmh->idFrom )
1070 /* Up folder button */
1071 case FCIDM_TB_UPFOLDER:
1072 stringId = IDS_UPFOLDER;
1073 break;
1074 /* New folder button */
1075 case FCIDM_TB_NEWFOLDER:
1076 stringId = IDS_NEWFOLDER;
1077 break;
1078 /* List option button */
1079 case FCIDM_TB_SMALLICON:
1080 stringId = IDS_LISTVIEW;
1081 break;
1082 /* Details option button */
1083 case FCIDM_TB_REPORTVIEW:
1084 stringId = IDS_REPORTVIEW;
1085 break;
1086 /* Desktop button */
1087 case FCIDM_TB_DESKTOP:
1088 stringId = IDS_TODESKTOP;
1089 break;
1090 default:
1091 stringId = 0;
1093 lpdi->hinst = COMDLG32_hInstance;
1094 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1096 return FALSE;
1098 default :
1099 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1100 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1101 return FALSE;
1105 /***********************************************************************
1106 * FILEDLG95_InitControls
1108 * WM_INITDIALOG message handler (before hook notification)
1110 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1112 int win2000plus = 0;
1113 int win98plus = 0;
1114 int handledPath = FALSE;
1115 OSVERSIONINFOA osVi;
1116 static const WCHAR szwSlash[] = { '\\', 0 };
1117 static const WCHAR szwStar[] = { '*',0 };
1119 TBBUTTON tbb[] =
1121 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1122 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1123 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1124 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1125 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1126 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1127 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1128 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1129 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1131 TBADDBITMAP tba[2];
1132 RECT rectTB;
1133 RECT rectlook;
1134 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1136 tba[0].hInst = HINST_COMMCTRL;
1137 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1138 tba[1].hInst = COMDLG32_hInstance;
1139 tba[1].nID = 800;
1141 TRACE("%p\n", fodInfos);
1143 /* Get windows version emulating */
1144 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1145 GetVersionExA(&osVi);
1146 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1147 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1148 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1149 win2000plus = (osVi.dwMajorVersion > 4);
1150 if (win2000plus) win98plus = TRUE;
1152 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1154 /* Get the hwnd of the controls */
1155 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1156 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1157 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1159 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1160 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1162 /* construct the toolbar */
1163 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1164 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1166 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1167 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1168 rectTB.left = rectlook.right;
1169 rectTB.top = rectlook.top-1;
1171 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1172 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1173 rectTB.left, rectTB.top,
1174 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1175 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1177 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1179 /* FIXME: use TB_LOADIMAGES when implemented */
1180 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1181 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1182 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1184 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1185 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1187 /* Set the window text with the text specified in the OPENFILENAME structure */
1188 if(fodInfos->title)
1190 SetWindowTextW(hwnd,fodInfos->title);
1192 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1194 WCHAR buf[16];
1195 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1196 SetWindowTextW(hwnd, buf);
1199 /* Initialise the file name edit control */
1200 handledPath = FALSE;
1201 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1203 if(fodInfos->filename)
1205 /* 1. If win2000 or higher and filename contains a path, use it
1206 in preference over the lpstrInitialDir */
1207 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1208 WCHAR tmpBuf[MAX_PATH];
1209 WCHAR *nameBit;
1210 DWORD result;
1212 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1213 if (result) {
1215 /* nameBit is always shorter than the original filename */
1216 strcpyW(fodInfos->filename,nameBit);
1218 *nameBit = 0x00;
1219 if (fodInfos->initdir == NULL)
1220 MemFree(fodInfos->initdir);
1221 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1222 strcpyW(fodInfos->initdir, tmpBuf);
1223 handledPath = TRUE;
1224 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1225 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1227 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1229 } else {
1230 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1234 /* 2. (All platforms) If initdir is not null, then use it */
1235 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1236 (*fodInfos->initdir!=0x00))
1238 /* Work out the proper path as supplied one might be relative */
1239 /* (Here because supplying '.' as dir browses to My Computer) */
1240 if (handledPath==FALSE) {
1241 WCHAR tmpBuf[MAX_PATH];
1242 WCHAR tmpBuf2[MAX_PATH];
1243 WCHAR *nameBit;
1244 DWORD result;
1246 strcpyW(tmpBuf, fodInfos->initdir);
1247 if( PathFileExistsW(tmpBuf) ) {
1248 /* initdir does not have to be a directory. If a file is
1249 * specified, the dir part is taken */
1250 if( PathIsDirectoryW(tmpBuf)) {
1251 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1252 strcatW(tmpBuf, szwSlash);
1254 strcatW(tmpBuf, szwStar);
1256 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1257 if (result) {
1258 *nameBit = 0x00;
1259 if (fodInfos->initdir)
1260 MemFree(fodInfos->initdir);
1261 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1262 strcpyW(fodInfos->initdir, tmpBuf2);
1263 handledPath = TRUE;
1264 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1267 else if (fodInfos->initdir)
1269 MemFree(fodInfos->initdir);
1270 fodInfos->initdir = NULL;
1271 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1276 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1277 (*fodInfos->initdir==0x00)))
1279 /* 3. All except w2k+: if filename contains a path use it */
1280 if (!win2000plus && fodInfos->filename &&
1281 *fodInfos->filename &&
1282 strpbrkW(fodInfos->filename, szwSlash)) {
1283 WCHAR tmpBuf[MAX_PATH];
1284 WCHAR *nameBit;
1285 DWORD result;
1287 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1288 tmpBuf, &nameBit);
1289 if (result) {
1290 int len;
1292 /* nameBit is always shorter than the original filename */
1293 strcpyW(fodInfos->filename, nameBit);
1294 *nameBit = 0x00;
1296 len = strlenW(tmpBuf);
1297 if(fodInfos->initdir)
1298 MemFree(fodInfos->initdir);
1299 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1300 strcpyW(fodInfos->initdir, tmpBuf);
1302 handledPath = TRUE;
1303 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1304 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1306 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1309 /* 4. win98+ and win2000+ if any files of specified filter types in
1310 current directory, use it */
1311 if ( win98plus && handledPath == FALSE &&
1312 fodInfos->filter && *fodInfos->filter) {
1314 BOOL searchMore = TRUE;
1315 LPCWSTR lpstrPos = fodInfos->filter;
1316 WIN32_FIND_DATAW FindFileData;
1317 HANDLE hFind;
1319 while (searchMore)
1321 /* filter is a list... title\0ext\0......\0\0 */
1323 /* Skip the title */
1324 if(! *lpstrPos) break; /* end */
1325 lpstrPos += strlenW(lpstrPos) + 1;
1327 /* See if any files exist in the current dir with this extension */
1328 if(! *lpstrPos) break; /* end */
1330 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1332 if (hFind == INVALID_HANDLE_VALUE) {
1333 /* None found - continue search */
1334 lpstrPos += strlenW(lpstrPos) + 1;
1336 } else {
1337 searchMore = FALSE;
1339 if(fodInfos->initdir)
1340 MemFree(fodInfos->initdir);
1341 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1342 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1344 handledPath = TRUE;
1345 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1346 debugstr_w(lpstrPos));
1347 break;
1352 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1354 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1355 if (handledPath == FALSE && (win2000plus || win98plus)) {
1356 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1358 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1360 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1362 /* last fallback */
1363 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1364 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1365 } else {
1366 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1368 } else {
1369 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1371 handledPath = TRUE;
1372 } else if (handledPath==FALSE) {
1373 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1374 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1375 handledPath = TRUE;
1376 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1379 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1380 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1382 /* Must the open as read only check box be checked ?*/
1383 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1385 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1388 /* Must the open as read only check box be hidden? */
1389 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1391 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1392 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1395 /* Must the help button be hidden? */
1396 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1398 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1399 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1402 /* Resize the height, if open as read only checkbox ad help button
1403 are hidden and we are not using a custom template nor a customDialog
1405 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1406 (!(fodInfos->ofnInfos->Flags &
1407 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1408 (!fodInfos->DlgInfos.hwndCustomDlg ))
1410 RECT rectDlg, rectHelp, rectCancel;
1411 GetWindowRect(hwnd, &rectDlg);
1412 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1413 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1414 /* subtract the height of the help button plus the space between
1415 the help button and the cancel button to the height of the dialog */
1416 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1417 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1418 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1420 /* change Open to Save */
1421 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1423 WCHAR buf[16];
1424 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1425 SetDlgItemTextW(hwnd, IDOK, buf);
1426 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1427 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1429 return 0;
1432 /***********************************************************************
1433 * FILEDLG95_FillControls
1435 * WM_INITDIALOG message handler (after hook notification)
1437 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1439 LPITEMIDLIST pidlItemId = NULL;
1441 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1443 TRACE("dir=%s file=%s\n",
1444 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1446 /* Get the initial directory pidl */
1448 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1450 WCHAR path[MAX_PATH];
1452 GetCurrentDirectoryW(MAX_PATH,path);
1453 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1456 /* Initialise shell objects */
1457 FILEDLG95_SHELL_Init(hwnd);
1459 /* Initialize the Look In combo box */
1460 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1462 /* Initialize the filter combo box */
1463 FILEDLG95_FILETYPE_Init(hwnd);
1465 /* Browse to the initial directory */
1466 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1468 /* Free pidlItem memory */
1469 COMDLG32_SHFree(pidlItemId);
1471 return TRUE;
1473 /***********************************************************************
1474 * FILEDLG95_Clean
1476 * Regroups all the cleaning functions of the filedlg
1478 void FILEDLG95_Clean(HWND hwnd)
1480 FILEDLG95_FILETYPE_Clean(hwnd);
1481 FILEDLG95_LOOKIN_Clean(hwnd);
1482 FILEDLG95_SHELL_Clean(hwnd);
1484 /***********************************************************************
1485 * FILEDLG95_OnWMCommand
1487 * WM_COMMAND message handler
1489 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1491 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1492 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1493 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1495 switch(wID)
1497 /* OK button */
1498 case IDOK:
1499 FILEDLG95_OnOpen(hwnd);
1500 break;
1501 /* Cancel button */
1502 case IDCANCEL:
1503 FILEDLG95_Clean(hwnd);
1504 EndDialog(hwnd, FALSE);
1505 break;
1506 /* Filetype combo box */
1507 case IDC_FILETYPE:
1508 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1509 break;
1510 /* LookIn combo box */
1511 case IDC_LOOKIN:
1512 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1513 break;
1515 /* --- toolbar --- */
1516 /* Up folder button */
1517 case FCIDM_TB_UPFOLDER:
1518 FILEDLG95_SHELL_UpFolder(hwnd);
1519 break;
1520 /* New folder button */
1521 case FCIDM_TB_NEWFOLDER:
1522 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1523 break;
1524 /* List option button */
1525 case FCIDM_TB_SMALLICON:
1526 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1527 break;
1528 /* Details option button */
1529 case FCIDM_TB_REPORTVIEW:
1530 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1531 break;
1532 /* Details option button */
1533 case FCIDM_TB_DESKTOP:
1534 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1535 break;
1537 case IDC_FILENAME:
1538 break;
1541 /* Do not use the listview selection anymore */
1542 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1543 return 0;
1546 /***********************************************************************
1547 * FILEDLG95_OnWMGetIShellBrowser
1549 * WM_GETISHELLBROWSER message handler
1551 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1554 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1556 TRACE("\n");
1558 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1560 return TRUE;
1564 /***********************************************************************
1565 * FILEDLG95_SendFileOK
1567 * Sends the CDN_FILEOK notification if required
1569 * RETURNS
1570 * TRUE if the dialog should close
1571 * FALSE if the dialog should not be closed
1573 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1575 /* ask the hook if we can close */
1576 if(IsHooked(fodInfos))
1578 TRACE("---\n");
1579 /* First send CDN_FILEOK as MSDN doc says */
1580 SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1581 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1583 TRACE("canceled\n");
1584 return FALSE;
1587 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1588 SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1589 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1590 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1592 TRACE("canceled\n");
1593 return FALSE;
1596 return TRUE;
1599 /***********************************************************************
1600 * FILEDLG95_OnOpenMultipleFiles
1602 * Handles the opening of multiple files.
1604 * FIXME
1605 * check destination buffer size
1607 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1609 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1610 UINT nCount, nSizePath;
1611 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1613 TRACE("\n");
1615 if(fodInfos->unicode)
1617 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1618 ofn->lpstrFile[0] = '\0';
1620 else
1622 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1623 ofn->lpstrFile[0] = '\0';
1626 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1628 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1629 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1630 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1632 LPWSTR lpstrTemp = lpstrFileList;
1634 for ( nCount = 0; nCount < nFileCount; nCount++ )
1636 LPITEMIDLIST pidl;
1638 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1639 if (!pidl)
1641 WCHAR lpstrNotFound[100];
1642 WCHAR lpstrMsg[100];
1643 WCHAR tmp[400];
1644 static const WCHAR nl[] = {'\n',0};
1646 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1647 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1649 strcpyW(tmp, lpstrTemp);
1650 strcatW(tmp, nl);
1651 strcatW(tmp, lpstrNotFound);
1652 strcatW(tmp, nl);
1653 strcatW(tmp, lpstrMsg);
1655 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1656 return FALSE;
1659 /* move to the next file in the list of files */
1660 lpstrTemp += strlenW(lpstrTemp) + 1;
1661 COMDLG32_SHFree(pidl);
1665 nSizePath = strlenW(lpstrPathSpec) + 1;
1666 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1668 /* For "oldstyle" dialog the components have to
1669 be separated by blanks (not '\0'!) and short
1670 filenames have to be used! */
1671 FIXME("Components have to be separated by blanks\n");
1673 if(fodInfos->unicode)
1675 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1676 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1677 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1679 else
1681 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1683 if (ofn->lpstrFile != NULL)
1685 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1686 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1687 if (ofn->nMaxFile > nSizePath)
1689 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1690 ofn->lpstrFile + nSizePath,
1691 ofn->nMaxFile - nSizePath, NULL, NULL);
1696 fodInfos->ofnInfos->nFileOffset = nSizePath;
1697 fodInfos->ofnInfos->nFileExtension = 0;
1699 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1700 return FALSE;
1702 /* clean and exit */
1703 FILEDLG95_Clean(hwnd);
1704 return EndDialog(hwnd,TRUE);
1707 /***********************************************************************
1708 * FILEDLG95_OnOpen
1710 * Ok button WM_COMMAND message handler
1712 * If the function succeeds, the return value is nonzero.
1714 #define ONOPEN_BROWSE 1
1715 #define ONOPEN_OPEN 2
1716 #define ONOPEN_SEARCH 3
1717 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1719 WCHAR strMsgTitle[MAX_PATH];
1720 WCHAR strMsgText [MAX_PATH];
1721 if (idCaption)
1722 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1723 else
1724 strMsgTitle[0] = '\0';
1725 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1726 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1729 BOOL FILEDLG95_OnOpen(HWND hwnd)
1731 LPWSTR lpstrFileList;
1732 UINT nFileCount = 0;
1733 UINT sizeUsed = 0;
1734 BOOL ret = TRUE;
1735 WCHAR lpstrPathAndFile[MAX_PATH];
1736 WCHAR lpstrTemp[MAX_PATH];
1737 LPSHELLFOLDER lpsf = NULL;
1738 int nOpenAction;
1739 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1741 TRACE("hwnd=%p\n", hwnd);
1743 /* get the files from the edit control */
1744 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1746 /* try if the user selected a folder in the shellview */
1747 if(nFileCount == 0)
1749 BrowseSelectedFolder(hwnd);
1750 return FALSE;
1753 if(nFileCount > 1)
1755 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1756 goto ret;
1759 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1762 Step 1: Build a complete path name from the current folder and
1763 the filename or path in the edit box.
1764 Special cases:
1765 - the path in the edit box is a root path
1766 (with or without drive letter)
1767 - the edit box contains ".." (or a path with ".." in it)
1770 /* Get the current directory name */
1771 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1773 /* last fallback */
1774 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1776 PathAddBackslashW(lpstrPathAndFile);
1778 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1780 /* if the user specifyed a fully qualified path use it */
1781 if(PathIsRelativeW(lpstrFileList))
1783 strcatW(lpstrPathAndFile, lpstrFileList);
1785 else
1787 /* does the path have a drive letter? */
1788 if (PathGetDriveNumberW(lpstrFileList) == -1)
1789 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1790 else
1791 strcpyW(lpstrPathAndFile, lpstrFileList);
1794 /* resolve "." and ".." */
1795 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1796 strcpyW(lpstrPathAndFile, lpstrTemp);
1797 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1799 MemFree(lpstrFileList);
1802 Step 2: here we have a cleaned up path
1804 We have to parse the path step by step to see if we have to browse
1805 to a folder if the path points to a directory or the last
1806 valid element is a directory.
1808 valid variables:
1809 lpstrPathAndFile: cleaned up path
1812 if (nFileCount &&
1813 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1814 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1815 nOpenAction = ONOPEN_OPEN;
1816 else
1817 nOpenAction = ONOPEN_BROWSE;
1819 /* don't apply any checks with OFN_NOVALIDATE */
1821 LPWSTR lpszTemp, lpszTemp1;
1822 LPITEMIDLIST pidl = NULL;
1823 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1825 /* check for invalid chars */
1826 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1828 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1829 ret = FALSE;
1830 goto ret;
1833 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1835 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1836 while (lpszTemp1)
1838 LPSHELLFOLDER lpsfChild;
1839 WCHAR lpwstrTemp[MAX_PATH];
1840 DWORD dwEaten, dwAttributes;
1841 LPWSTR p;
1843 strcpyW(lpwstrTemp, lpszTemp);
1844 p = PathFindNextComponentW(lpwstrTemp);
1846 if (!p) break; /* end of path */
1848 *p = 0;
1849 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1851 /* There are no wildcards when OFN_NOVALIDATE is set */
1852 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1854 static const WCHAR wszWild[] = { '*', '?', 0 };
1855 /* if the last element is a wildcard do a search */
1856 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1858 nOpenAction = ONOPEN_SEARCH;
1859 break;
1862 lpszTemp1 = lpszTemp;
1864 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1866 /* append a backslash to drive letters */
1867 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1868 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1869 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1871 PathAddBackslashW(lpwstrTemp);
1874 dwAttributes = SFGAO_FOLDER;
1875 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1877 /* the path component is valid, we have a pidl of the next path component */
1878 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1879 if(dwAttributes & SFGAO_FOLDER)
1881 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1883 ERR("bind to failed\n"); /* should not fail */
1884 break;
1886 IShellFolder_Release(lpsf);
1887 lpsf = lpsfChild;
1888 lpsfChild = NULL;
1890 else
1892 TRACE("value\n");
1894 /* end dialog, return value */
1895 nOpenAction = ONOPEN_OPEN;
1896 break;
1898 COMDLG32_SHFree(pidl);
1899 pidl = NULL;
1901 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1903 if(*lpszTemp) /* points to trailing null for last path element */
1905 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1907 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1908 break;
1911 else
1913 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1914 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1916 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1917 break;
1920 /* change to the current folder */
1921 nOpenAction = ONOPEN_OPEN;
1922 break;
1924 else
1926 nOpenAction = ONOPEN_OPEN;
1927 break;
1930 if(pidl) COMDLG32_SHFree(pidl);
1934 Step 3: here we have a cleaned up and validated path
1936 valid variables:
1937 lpsf: ShellFolder bound to the rightmost valid path component
1938 lpstrPathAndFile: cleaned up path
1939 nOpenAction: action to do
1941 TRACE("end validate sf=%p\n", lpsf);
1943 switch(nOpenAction)
1945 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1946 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1948 int iPos;
1949 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1950 DWORD len;
1952 /* replace the current filter */
1953 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1954 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1955 len = strlenW(lpszTemp)+1;
1956 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1957 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1959 /* set the filter cb to the extension when possible */
1960 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1961 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1963 /* fall through */
1964 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1965 TRACE("ONOPEN_BROWSE\n");
1967 IPersistFolder2 * ppf2;
1968 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1970 LPITEMIDLIST pidlCurrent;
1971 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1972 IPersistFolder2_Release(ppf2);
1973 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1975 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1977 else if( nOpenAction == ONOPEN_SEARCH )
1979 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1981 COMDLG32_SHFree(pidlCurrent);
1984 ret = FALSE;
1985 break;
1986 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
1987 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
1989 WCHAR *ext = NULL;
1991 /* update READONLY check box flag */
1992 if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
1993 fodInfos->ofnInfos->Flags |= OFN_READONLY;
1994 else
1995 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
1997 /* Attach the file extension with file name*/
1998 ext = PathFindExtensionW(lpstrPathAndFile);
1999 if (! *ext)
2001 /* if no extension is specified with file name, then */
2002 /* attach the extension from file filter or default one */
2004 WCHAR *filterExt = NULL;
2005 LPWSTR lpstrFilter = NULL;
2006 static const WCHAR szwDot[] = {'.',0};
2007 int PathLength = strlenW(lpstrPathAndFile);
2009 /* Attach the dot*/
2010 strcatW(lpstrPathAndFile, szwDot);
2012 /*Get the file extension from file type filter*/
2013 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2014 fodInfos->ofnInfos->nFilterIndex-1);
2016 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2017 filterExt = PathFindExtensionW(lpstrFilter);
2019 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2020 strcatW(lpstrPathAndFile, filterExt + 1);
2021 else if ( fodInfos->defext ) /* attach the default file extension*/
2022 strcatW(lpstrPathAndFile, fodInfos->defext);
2024 /* In Open dialog: if file does not exist try without extension */
2025 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2026 lpstrPathAndFile[PathLength] = '\0';
2029 if (fodInfos->defext) /* add default extension */
2031 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2032 if (*ext)
2033 ext++;
2034 if (!lstrcmpiW(fodInfos->defext, ext))
2035 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2036 else
2037 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2040 /* In Save dialog: check if the file already exists */
2041 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2042 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2043 && PathFileExistsW(lpstrPathAndFile))
2045 WCHAR lpstrOverwrite[100];
2046 int answer;
2048 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2049 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2050 MB_YESNO | MB_ICONEXCLAMATION);
2051 if (answer == IDNO)
2053 ret = FALSE;
2054 goto ret;
2058 /* Check that the size of the file does not exceed buffer size.
2059 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2060 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2061 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2063 LPWSTR lpszTemp;
2065 /* fill destination buffer */
2066 if (fodInfos->ofnInfos->lpstrFile)
2068 if(fodInfos->unicode)
2070 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2072 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2073 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2074 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2076 else
2078 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2080 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2081 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2082 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2083 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2087 /* set filename offset */
2088 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2089 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2091 /* set extension offset */
2092 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2093 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2095 /* set the lpstrFileTitle */
2096 if(fodInfos->ofnInfos->lpstrFileTitle)
2098 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2099 if(fodInfos->unicode)
2101 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2102 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2104 else
2106 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2107 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2108 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2112 /* copy currently selected filter to lpstrCustomFilter */
2113 if (fodInfos->ofnInfos->lpstrCustomFilter)
2115 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2116 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2117 NULL, 0, NULL, NULL);
2118 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2120 LPSTR s = ofn->lpstrCustomFilter;
2121 s += strlen(ofn->lpstrCustomFilter)+1;
2122 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2123 s, len, NULL, NULL);
2128 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2129 goto ret;
2131 TRACE("close\n");
2132 FILEDLG95_Clean(hwnd);
2133 ret = EndDialog(hwnd, TRUE);
2135 else
2137 WORD size;
2139 size = strlenW(lpstrPathAndFile) + 1;
2140 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2141 size += 1;
2142 /* return needed size in first two bytes of lpstrFile */
2143 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2144 FILEDLG95_Clean(hwnd);
2145 ret = EndDialog(hwnd, FALSE);
2146 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2148 goto ret;
2150 break;
2153 ret:
2154 if(lpsf) IShellFolder_Release(lpsf);
2155 return ret;
2158 /***********************************************************************
2159 * FILEDLG95_SHELL_Init
2161 * Initialisation of the shell objects
2163 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2165 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2167 TRACE("\n");
2170 * Initialisation of the FileOpenDialogInfos structure
2173 /* Shell */
2175 /*ShellInfos */
2176 fodInfos->ShellInfos.hwndOwner = hwnd;
2178 /* Disable multi-select if flag not set */
2179 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2181 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2183 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2184 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2186 /* Construct the IShellBrowser interface */
2187 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2189 return NOERROR;
2192 /***********************************************************************
2193 * FILEDLG95_SHELL_ExecuteCommand
2195 * Change the folder option and refresh the view
2196 * If the function succeeds, the return value is nonzero.
2198 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2200 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2202 IContextMenu * pcm;
2203 TRACE("(%p,%p)\n", hwnd, lpVerb);
2205 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2206 SVGIO_BACKGROUND,
2207 &IID_IContextMenu,
2208 (LPVOID*)&pcm)))
2210 CMINVOKECOMMANDINFO ci;
2211 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2212 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2213 ci.lpVerb = lpVerb;
2214 ci.hwnd = hwnd;
2216 IContextMenu_InvokeCommand(pcm, &ci);
2217 IContextMenu_Release(pcm);
2220 return FALSE;
2223 /***********************************************************************
2224 * FILEDLG95_SHELL_UpFolder
2226 * Browse to the specified object
2227 * If the function succeeds, the return value is nonzero.
2229 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2231 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2233 TRACE("\n");
2235 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2236 NULL,
2237 SBSP_PARENT)))
2239 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2240 return TRUE;
2242 return FALSE;
2245 /***********************************************************************
2246 * FILEDLG95_SHELL_BrowseToDesktop
2248 * Browse to the Desktop
2249 * If the function succeeds, the return value is nonzero.
2251 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2253 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2254 LPITEMIDLIST pidl;
2255 HRESULT hres;
2257 TRACE("\n");
2259 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2260 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2261 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2262 COMDLG32_SHFree(pidl);
2263 return SUCCEEDED(hres);
2265 /***********************************************************************
2266 * FILEDLG95_SHELL_Clean
2268 * Cleans the memory used by shell objects
2270 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2272 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2274 TRACE("\n");
2276 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2278 /* clean Shell interfaces */
2279 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2280 IShellView_Release(fodInfos->Shell.FOIShellView);
2281 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2282 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2283 if (fodInfos->Shell.FOIDataObject)
2284 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2287 /***********************************************************************
2288 * FILEDLG95_FILETYPE_Init
2290 * Initialisation of the file type combo box
2292 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2294 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2295 int nFilters = 0; /* number of filters */
2296 int nFilterIndexCB;
2298 TRACE("\n");
2300 if(fodInfos->customfilter)
2302 /* customfilter has one entry... title\0ext\0
2303 * Set first entry of combo box item with customfilter
2305 LPWSTR lpstrExt;
2306 LPCWSTR lpstrPos = fodInfos->customfilter;
2308 /* Get the title */
2309 lpstrPos += strlenW(fodInfos->customfilter) + 1;
2311 /* Copy the extensions */
2312 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2313 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2314 strcpyW(lpstrExt,lpstrPos);
2316 /* Add the item at the end of the combo */
2317 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2318 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2319 nFilters++;
2321 if(fodInfos->filter)
2323 LPCWSTR lpstrPos = fodInfos->filter;
2325 for(;;)
2327 /* filter is a list... title\0ext\0......\0\0
2328 * Set the combo item text to the title and the item data
2329 * to the ext
2331 LPCWSTR lpstrDisplay;
2332 LPWSTR lpstrExt;
2334 /* Get the title */
2335 if(! *lpstrPos) break; /* end */
2336 lpstrDisplay = lpstrPos;
2337 lpstrPos += strlenW(lpstrPos) + 1;
2339 /* Copy the extensions */
2340 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2341 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2342 strcpyW(lpstrExt,lpstrPos);
2343 lpstrPos += strlenW(lpstrPos) + 1;
2345 /* Add the item at the end of the combo */
2346 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2347 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2348 nFilters++;
2353 * Set the current filter to the one specified
2354 * in the initialisation structure
2356 if (fodInfos->filter || fodInfos->customfilter)
2358 LPWSTR lpstrFilter;
2360 /* Check to make sure our index isn't out of bounds. */
2361 if ( fodInfos->ofnInfos->nFilterIndex >
2362 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2363 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2365 /* set default filter index */
2366 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2367 fodInfos->ofnInfos->nFilterIndex = 1;
2369 /* calculate index of Combo Box item */
2370 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2371 if (fodInfos->customfilter == NULL)
2372 nFilterIndexCB--;
2374 /* Set the current index selection. */
2375 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2377 /* Get the corresponding text string from the combo box. */
2378 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2379 nFilterIndexCB);
2381 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2382 lpstrFilter = NULL;
2384 if(lpstrFilter)
2386 DWORD len;
2387 CharLowerW(lpstrFilter); /* lowercase */
2388 len = strlenW(lpstrFilter)+1;
2389 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2390 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2392 } else
2393 fodInfos->ofnInfos->nFilterIndex = 0;
2394 return S_OK;
2397 /***********************************************************************
2398 * FILEDLG95_FILETYPE_OnCommand
2400 * WM_COMMAND of the file type combo box
2401 * If the function succeeds, the return value is nonzero.
2403 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2405 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2407 switch(wNotifyCode)
2409 case CBN_SELENDOK:
2411 LPWSTR lpstrFilter;
2413 /* Get the current item of the filetype combo box */
2414 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2416 /* set the current filter index */
2417 fodInfos->ofnInfos->nFilterIndex = iItem +
2418 (fodInfos->customfilter == NULL ? 1 : 0);
2420 /* Set the current filter with the current selection */
2421 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2422 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2424 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2425 iItem);
2426 if((INT_PTR)lpstrFilter != CB_ERR)
2428 DWORD len;
2429 CharLowerW(lpstrFilter); /* lowercase */
2430 len = strlenW(lpstrFilter)+1;
2431 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2432 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2433 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2436 /* Refresh the actual view to display the included items*/
2437 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2440 return FALSE;
2442 /***********************************************************************
2443 * FILEDLG95_FILETYPE_SearchExt
2445 * searches for an extension in the filetype box
2447 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2449 int i, iCount = CBGetCount(hwnd);
2451 TRACE("%s\n", debugstr_w(lpstrExt));
2453 if(iCount != CB_ERR)
2455 for(i=0;i<iCount;i++)
2457 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2458 return i;
2461 return -1;
2464 /***********************************************************************
2465 * FILEDLG95_FILETYPE_Clean
2467 * Clean the memory used by the filetype combo box
2469 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2471 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2472 int iPos;
2473 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2475 TRACE("\n");
2477 /* Delete each string of the combo and their associated data */
2478 if(iCount != CB_ERR)
2480 for(iPos = iCount-1;iPos>=0;iPos--)
2482 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2483 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2486 /* Current filter */
2487 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2488 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2492 /***********************************************************************
2493 * FILEDLG95_LOOKIN_Init
2495 * Initialisation of the look in combo box
2498 /* Small helper function, to determine if the unixfs shell extension is rooted
2499 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2501 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2502 HKEY hKey;
2503 const static WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2504 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2505 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2506 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2507 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2508 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2509 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2511 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2512 return FALSE;
2514 RegCloseKey(hKey);
2515 return TRUE;
2518 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2520 IShellFolder *psfRoot, *psfDrives;
2521 IEnumIDList *lpeRoot, *lpeDrives;
2522 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2524 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2526 TRACE("\n");
2528 liInfos->iMaxIndentation = 0;
2530 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2532 /* set item height for both text field and listbox */
2533 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2534 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2536 /* Turn on the extended UI for the combo box like Windows does */
2537 CBSetExtendedUI(hwndCombo, TRUE);
2539 /* Initialise data of Desktop folder */
2540 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2541 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2542 COMDLG32_SHFree(pidlTmp);
2544 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2546 SHGetDesktopFolder(&psfRoot);
2548 if (psfRoot)
2550 /* enumerate the contents of the desktop */
2551 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2553 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2555 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2557 /* If the unixfs extension is rooted, we don't expand the drives by default */
2558 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2560 /* special handling for CSIDL_DRIVES */
2561 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2563 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2565 /* enumerate the drives */
2566 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2568 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2570 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2571 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2572 COMDLG32_SHFree(pidlAbsTmp);
2573 COMDLG32_SHFree(pidlTmp1);
2575 IEnumIDList_Release(lpeDrives);
2577 IShellFolder_Release(psfDrives);
2582 COMDLG32_SHFree(pidlTmp);
2584 IEnumIDList_Release(lpeRoot);
2586 IShellFolder_Release(psfRoot);
2589 COMDLG32_SHFree(pidlDrives);
2592 /***********************************************************************
2593 * FILEDLG95_LOOKIN_DrawItem
2595 * WM_DRAWITEM message handler
2597 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2599 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2600 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2601 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2602 RECT rectText;
2603 RECT rectIcon;
2604 SHFILEINFOA sfi;
2605 HIMAGELIST ilItemImage;
2606 int iIndentation;
2607 TEXTMETRICA tm;
2608 LPSFOLDER tmpFolder;
2611 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2613 TRACE("\n");
2615 if(pDIStruct->itemID == -1)
2616 return 0;
2618 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2619 pDIStruct->itemID)))
2620 return 0;
2623 if(pDIStruct->itemID == liInfos->uSelectedItem)
2625 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2627 &sfi,
2628 sizeof (SHFILEINFOA),
2629 SHGFI_PIDL | SHGFI_SMALLICON |
2630 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2631 SHGFI_DISPLAYNAME );
2633 else
2635 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2637 &sfi,
2638 sizeof (SHFILEINFOA),
2639 SHGFI_PIDL | SHGFI_SMALLICON |
2640 SHGFI_SYSICONINDEX |
2641 SHGFI_DISPLAYNAME);
2644 /* Is this item selected ? */
2645 if(pDIStruct->itemState & ODS_SELECTED)
2647 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2648 SetBkColor(pDIStruct->hDC,crHighLight);
2649 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2651 else
2653 SetTextColor(pDIStruct->hDC,crText);
2654 SetBkColor(pDIStruct->hDC,crWin);
2655 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2658 /* Do not indent item if drawing in the edit of the combo */
2659 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2661 iIndentation = 0;
2662 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2664 &sfi,
2665 sizeof (SHFILEINFOA),
2666 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2667 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2670 else
2672 iIndentation = tmpFolder->m_iIndent;
2674 /* Draw text and icon */
2676 /* Initialise the icon display area */
2677 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2678 rectIcon.top = pDIStruct->rcItem.top;
2679 rectIcon.right = rectIcon.left + ICONWIDTH;
2680 rectIcon.bottom = pDIStruct->rcItem.bottom;
2682 /* Initialise the text display area */
2683 GetTextMetricsA(pDIStruct->hDC, &tm);
2684 rectText.left = rectIcon.right;
2685 rectText.top =
2686 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2687 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2688 rectText.bottom =
2689 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2691 /* Draw the icon from the image list */
2692 ImageList_Draw(ilItemImage,
2693 sfi.iIcon,
2694 pDIStruct->hDC,
2695 rectIcon.left,
2696 rectIcon.top,
2697 ILD_TRANSPARENT );
2699 /* Draw the associated text */
2700 if(sfi.szDisplayName)
2701 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2704 return NOERROR;
2707 /***********************************************************************
2708 * FILEDLG95_LOOKIN_OnCommand
2710 * LookIn combo box WM_COMMAND message handler
2711 * If the function succeeds, the return value is nonzero.
2713 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2715 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2717 TRACE("%p\n", fodInfos);
2719 switch(wNotifyCode)
2721 case CBN_SELENDOK:
2723 LPSFOLDER tmpFolder;
2724 int iItem;
2726 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2728 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2729 iItem)))
2730 return FALSE;
2733 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2734 tmpFolder->pidlItem,
2735 SBSP_ABSOLUTE)))
2737 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2738 return TRUE;
2740 break;
2744 return FALSE;
2747 /***********************************************************************
2748 * FILEDLG95_LOOKIN_AddItem
2750 * Adds an absolute pidl item to the lookin combo box
2751 * returns the index of the inserted item
2753 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2755 LPITEMIDLIST pidlNext;
2756 SHFILEINFOA sfi;
2757 SFOLDER *tmpFolder;
2758 LookInInfos *liInfos;
2760 TRACE("%08x\n", iInsertId);
2762 if(!pidl)
2763 return -1;
2765 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2766 return -1;
2768 tmpFolder = MemAlloc(sizeof(SFOLDER));
2769 tmpFolder->m_iIndent = 0;
2771 /* Calculate the indentation of the item in the lookin*/
2772 pidlNext = pidl;
2773 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2775 tmpFolder->m_iIndent++;
2778 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2780 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2781 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2783 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2784 SHGetFileInfoA((LPSTR)pidl,
2786 &sfi,
2787 sizeof(sfi),
2788 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2789 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2791 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2793 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2795 int iItemID;
2797 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2799 /* Add the item at the end of the list */
2800 if(iInsertId < 0)
2802 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2804 /* Insert the item at the iInsertId position*/
2805 else
2807 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2810 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2811 return iItemID;
2814 COMDLG32_SHFree( tmpFolder->pidlItem );
2815 MemFree( tmpFolder );
2816 return -1;
2820 /***********************************************************************
2821 * FILEDLG95_LOOKIN_InsertItemAfterParent
2823 * Insert an item below its parent
2825 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2828 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2829 int iParentPos;
2831 TRACE("\n");
2833 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2835 if(iParentPos < 0)
2837 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2840 /* Free pidlParent memory */
2841 COMDLG32_SHFree((LPVOID)pidlParent);
2843 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2846 /***********************************************************************
2847 * FILEDLG95_LOOKIN_SelectItem
2849 * Adds an absolute pidl item to the lookin combo box
2850 * returns the index of the inserted item
2852 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2854 int iItemPos;
2855 LookInInfos *liInfos;
2857 TRACE("\n");
2859 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2861 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2863 if(iItemPos < 0)
2865 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2866 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2869 else
2871 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2872 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2874 int iRemovedItem;
2876 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2877 break;
2878 if(iRemovedItem < iItemPos)
2879 iItemPos--;
2883 CBSetCurSel(hwnd,iItemPos);
2884 liInfos->uSelectedItem = iItemPos;
2886 return 0;
2890 /***********************************************************************
2891 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2893 * Remove the item with an expansion level over iExpansionLevel
2895 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2897 int iItemPos;
2899 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2901 TRACE("\n");
2903 if(liInfos->iMaxIndentation <= 2)
2904 return -1;
2906 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2908 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2909 COMDLG32_SHFree(tmpFolder->pidlItem);
2910 MemFree(tmpFolder);
2911 CBDeleteString(hwnd,iItemPos);
2912 liInfos->iMaxIndentation--;
2914 return iItemPos;
2917 return -1;
2920 /***********************************************************************
2921 * FILEDLG95_LOOKIN_SearchItem
2923 * Search for pidl in the lookin combo box
2924 * returns the index of the found item
2926 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2928 int i = 0;
2929 int iCount = CBGetCount(hwnd);
2931 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2933 if (iCount != CB_ERR)
2935 for(;i<iCount;i++)
2937 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2939 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2940 return i;
2941 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2942 return i;
2946 return -1;
2949 /***********************************************************************
2950 * FILEDLG95_LOOKIN_Clean
2952 * Clean the memory used by the lookin combo box
2954 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2956 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2957 int iPos;
2958 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2960 TRACE("\n");
2962 /* Delete each string of the combo and their associated data */
2963 if (iCount != CB_ERR)
2965 for(iPos = iCount-1;iPos>=0;iPos--)
2967 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
2968 COMDLG32_SHFree(tmpFolder->pidlItem);
2969 MemFree(tmpFolder);
2970 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
2974 /* LookInInfos structure */
2975 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
2978 /***********************************************************************
2979 * FILEDLG95_FILENAME_FillFromSelection
2981 * fills the edit box from the cached DataObject
2983 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
2985 FileOpenDlgInfos *fodInfos;
2986 LPITEMIDLIST pidl;
2987 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
2988 char lpstrTemp[MAX_PATH];
2989 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
2991 TRACE("\n");
2992 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2994 /* Count how many files we have */
2995 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
2997 /* calculate the string length, count files */
2998 if (nFileSelected >= 1)
3000 nLength += 3; /* first and last quotes, trailing \0 */
3001 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3003 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3005 if (pidl)
3007 /* get the total length of the selected file names */
3008 lpstrTemp[0] = '\0';
3009 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3011 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3013 nLength += strlen( lpstrTemp ) + 3;
3014 nFiles++;
3016 COMDLG32_SHFree( pidl );
3021 /* allocate the buffer */
3022 if (nFiles <= 1) nLength = MAX_PATH;
3023 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
3024 lpstrAllFile[0] = '\0';
3026 /* Generate the string for the edit control */
3027 if(nFiles >= 1)
3029 lpstrCurrFile = lpstrAllFile;
3030 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3032 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3034 if (pidl)
3036 /* get the file name */
3037 lpstrTemp[0] = '\0';
3038 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3040 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3042 if ( nFiles > 1)
3044 *lpstrCurrFile++ = '\"';
3045 strcpy( lpstrCurrFile, lpstrTemp );
3046 lpstrCurrFile += strlen( lpstrTemp );
3047 strcpy( lpstrCurrFile, "\" " );
3048 lpstrCurrFile += 2;
3050 else
3052 strcpy( lpstrAllFile, lpstrTemp );
3055 COMDLG32_SHFree( (LPVOID) pidl );
3058 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3060 /* Select the file name like Windows does */
3061 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
3063 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3067 /* copied from shell32 to avoid linking to it
3068 * FIXME: why? shell32 is already linked
3070 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3072 switch (src->uType)
3074 case STRRET_WSTR:
3075 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
3076 COMDLG32_SHFree(src->u.pOleStr);
3077 break;
3079 case STRRET_CSTR:
3080 lstrcpynA((LPSTR)dest, src->u.cStr, len);
3081 break;
3083 case STRRET_OFFSET:
3084 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
3085 break;
3087 default:
3088 FIXME("unknown type!\n");
3089 if (len)
3091 *(LPSTR)dest = '\0';
3093 return(E_FAIL);
3095 return S_OK;
3098 /***********************************************************************
3099 * FILEDLG95_FILENAME_GetFileNames
3101 * Copies the filenames to a delimited string list.
3102 * The delimiter is specified by the parameter 'separator',
3103 * usually either a space or a nul
3105 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3107 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3108 UINT nStrCharCount = 0; /* index in src buffer */
3109 UINT nFileIndex = 0; /* index in dest buffer */
3110 UINT nFileCount = 0; /* number of files */
3111 UINT nStrLen = 0; /* length of string in edit control */
3112 LPWSTR lpstrEdit; /* buffer for string from edit control */
3114 TRACE("\n");
3116 /* get the filenames from the edit control */
3117 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3118 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3119 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3121 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3123 /* we might get single filename without any '"',
3124 * so we need nStrLen + terminating \0 + end-of-list \0 */
3125 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3126 *sizeUsed = 0;
3128 /* build delimited file list from filenames */
3129 while ( nStrCharCount <= nStrLen )
3131 if ( lpstrEdit[nStrCharCount]=='"' )
3133 nStrCharCount++;
3134 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3136 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3137 (*sizeUsed)++;
3138 nStrCharCount++;
3140 (*lpstrFileList)[nFileIndex++] = separator;
3141 (*sizeUsed)++;
3142 nFileCount++;
3144 nStrCharCount++;
3147 /* single, unquoted string */
3148 if ((nStrLen > 0) && (*sizeUsed == 0) )
3150 strcpyW(*lpstrFileList, lpstrEdit);
3151 nFileIndex = strlenW(lpstrEdit) + 1;
3152 (*sizeUsed) = nFileIndex;
3153 nFileCount = 1;
3156 /* trailing \0 */
3157 (*lpstrFileList)[nFileIndex] = '\0';
3158 (*sizeUsed)++;
3160 MemFree(lpstrEdit);
3161 return nFileCount;
3164 #define SETDefFormatEtc(fe,cf,med) \
3166 (fe).cfFormat = cf;\
3167 (fe).dwAspect = DVASPECT_CONTENT; \
3168 (fe).ptd =NULL;\
3169 (fe).tymed = med;\
3170 (fe).lindex = -1;\
3174 * DATAOBJECT Helper functions
3177 /***********************************************************************
3178 * COMCTL32_ReleaseStgMedium
3180 * like ReleaseStgMedium from ole32
3182 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3184 if(medium.pUnkForRelease)
3186 IUnknown_Release(medium.pUnkForRelease);
3188 else
3190 GlobalUnlock(medium.u.hGlobal);
3191 GlobalFree(medium.u.hGlobal);
3195 /***********************************************************************
3196 * GetPidlFromDataObject
3198 * Return pidl(s) by number from the cached DataObject
3200 * nPidlIndex=0 gets the fully qualified root path
3202 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3205 STGMEDIUM medium;
3206 FORMATETC formatetc;
3207 LPITEMIDLIST pidl = NULL;
3209 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3211 if (!doSelected)
3212 return NULL;
3214 /* Set the FORMATETC structure*/
3215 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3217 /* Get the pidls from IDataObject */
3218 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3220 LPIDA cida = GlobalLock(medium.u.hGlobal);
3221 if(nPidlIndex <= cida->cidl)
3223 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3225 COMCTL32_ReleaseStgMedium(medium);
3227 return pidl;
3230 /***********************************************************************
3231 * GetNumSelected
3233 * Return the number of selected items in the DataObject.
3236 UINT GetNumSelected( IDataObject *doSelected )
3238 UINT retVal = 0;
3239 STGMEDIUM medium;
3240 FORMATETC formatetc;
3242 TRACE("sv=%p\n", doSelected);
3244 if (!doSelected) return 0;
3246 /* Set the FORMATETC structure*/
3247 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3249 /* Get the pidls from IDataObject */
3250 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3252 LPIDA cida = GlobalLock(medium.u.hGlobal);
3253 retVal = cida->cidl;
3254 COMCTL32_ReleaseStgMedium(medium);
3255 return retVal;
3257 return 0;
3261 * TOOLS
3264 /***********************************************************************
3265 * GetName
3267 * Get the pidl's display name (relative to folder) and
3268 * put it in lpstrFileName.
3270 * Return NOERROR on success,
3271 * E_FAIL otherwise
3274 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3276 STRRET str;
3277 HRESULT hRes;
3279 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3281 if(!lpsf)
3283 SHGetDesktopFolder(&lpsf);
3284 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3285 IShellFolder_Release(lpsf);
3286 return hRes;
3289 /* Get the display name of the pidl relative to the folder */
3290 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3292 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3294 return E_FAIL;
3297 /***********************************************************************
3298 * GetShellFolderFromPidl
3300 * pidlRel is the item pidl relative
3301 * Return the IShellFolder of the absolute pidl
3303 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3305 IShellFolder *psf = NULL,*psfParent;
3307 TRACE("%p\n", pidlAbs);
3309 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3311 psf = psfParent;
3312 if(pidlAbs && pidlAbs->mkid.cb)
3314 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3316 IShellFolder_Release(psfParent);
3317 return psf;
3320 /* return the desktop */
3321 return psfParent;
3323 return NULL;
3326 /***********************************************************************
3327 * GetParentPidl
3329 * Return the LPITEMIDLIST to the parent of the pidl in the list
3331 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3333 LPITEMIDLIST pidlParent;
3335 TRACE("%p\n", pidl);
3337 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3338 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3340 return pidlParent;
3343 /***********************************************************************
3344 * GetPidlFromName
3346 * returns the pidl of the file name relative to folder
3347 * NULL if an error occurred
3349 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3351 LPITEMIDLIST pidl = NULL;
3352 ULONG ulEaten;
3354 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3356 if(!lpcstrFileName) return NULL;
3357 if(!*lpcstrFileName) return NULL;
3359 if(!lpsf)
3361 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3362 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3363 IShellFolder_Release(lpsf);
3366 else
3368 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3370 return pidl;
3375 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3377 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3378 HRESULT ret;
3380 TRACE("%p, %p\n", psf, pidl);
3382 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3384 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3385 /* see documentation shell 4.1*/
3386 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3389 /***********************************************************************
3390 * BrowseSelectedFolder
3392 static BOOL BrowseSelectedFolder(HWND hwnd)
3394 BOOL bBrowseSelFolder = FALSE;
3395 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3397 TRACE("\n");
3399 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3401 LPITEMIDLIST pidlSelection;
3403 /* get the file selected */
3404 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3405 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3407 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3408 pidlSelection, SBSP_RELATIVE ) ) )
3410 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3411 ' ','n','o','t',' ','e','x','i','s','t',0};
3412 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3414 bBrowseSelFolder = TRUE;
3415 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3417 COMDLG32_SHFree( pidlSelection );
3420 return bBrowseSelFolder;
3424 * Memory allocation methods */
3425 static void *MemAlloc(UINT size)
3427 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3430 static void MemFree(void *mem)
3432 HeapFree(GetProcessHeap(),0,mem);
3436 * Old-style (win3.1) dialogs */
3438 /***********************************************************************
3439 * FD32_GetTemplate [internal]
3441 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3442 * by a 32 bits application
3445 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3447 LPOPENFILENAMEW ofnW = lfs->ofnW;
3448 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3449 HANDLE hDlgTmpl;
3451 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3453 if (!(lfs->template = LockResource( ofnW->hInstance )))
3455 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3456 return FALSE;
3459 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3461 HRSRC hResInfo;
3462 if (priv->ofnA)
3463 hResInfo = FindResourceA(priv->ofnA->hInstance,
3464 priv->ofnA->lpTemplateName,
3465 (LPSTR)RT_DIALOG);
3466 else
3467 hResInfo = FindResourceW(ofnW->hInstance,
3468 ofnW->lpTemplateName,
3469 (LPWSTR)RT_DIALOG);
3470 if (!hResInfo)
3472 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3473 return FALSE;
3475 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3476 hResInfo)) ||
3477 !(lfs->template = LockResource(hDlgTmpl)))
3479 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3480 return FALSE;
3482 } else { /* get it from internal Wine resource */
3483 HRSRC hResInfo;
3484 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3485 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3487 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3488 return FALSE;
3490 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3491 !(lfs->template = LockResource( hDlgTmpl )))
3493 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3494 return FALSE;
3497 return TRUE;
3501 /************************************************************************
3502 * FD32_Init [internal]
3503 * called from the common 16/32 code to initialize 32 bit data
3505 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3507 BOOL IsUnicode = (BOOL) data;
3508 PFD32_PRIVATE priv;
3510 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3511 lfs->private1632 = priv;
3512 if (NULL == lfs->private1632) return FALSE;
3513 if (IsUnicode)
3515 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3516 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3517 if (lfs->ofnW->lpfnHook)
3518 lfs->hook = TRUE;
3520 else
3522 priv->ofnA = (LPOPENFILENAMEA) lParam;
3523 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3524 if (priv->ofnA->lpfnHook)
3525 lfs->hook = TRUE;
3526 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3527 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3530 if (! FD32_GetTemplate(lfs)) return FALSE;
3532 return TRUE;
3535 /***********************************************************************
3536 * FD32_CallWindowProc [internal]
3538 * called from the common 16/32 code to call the appropriate hook
3540 static BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
3541 LPARAM lParam)
3543 BOOL ret;
3544 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3546 if (priv->ofnA)
3548 TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3549 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3550 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3551 TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3552 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3553 return ret;
3556 TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3557 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3558 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3559 TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3560 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3561 return ret;
3564 /***********************************************************************
3565 * FD32_UpdateResult [internal]
3566 * update the real client structures if any
3568 static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs)
3570 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3571 LPOPENFILENAMEW ofnW = lfs->ofnW;
3573 if (priv->ofnA)
3575 if (ofnW->nMaxFile &&
3576 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3577 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3578 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3579 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3580 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3584 /***********************************************************************
3585 * FD32_UpdateFileTitle [internal]
3586 * update the real client structures if any
3588 static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs)
3590 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3591 LPOPENFILENAMEW ofnW = lfs->ofnW;
3593 if (priv->ofnA)
3595 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3596 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3597 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3602 /***********************************************************************
3603 * FD32_SendLbGetCurSel [internal]
3604 * retrieve selected listbox item
3606 static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs)
3608 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3612 /************************************************************************
3613 * FD32_Destroy [internal]
3614 * called from the common 16/32 code to cleanup 32 bit data
3616 static void CALLBACK FD32_Destroy(PFD31_DATA lfs)
3618 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3620 /* if ofnW has been allocated, have to free everything in it */
3621 if (NULL != priv && NULL != priv->ofnA)
3623 FD31_FreeOfnW(lfs->ofnW);
3624 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3628 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3630 callbacks->Init = FD32_Init;
3631 callbacks->CWP = FD32_CallWindowProc;
3632 callbacks->UpdateResult = FD32_UpdateResult;
3633 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3634 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3635 callbacks->Destroy = FD32_Destroy;
3638 /***********************************************************************
3639 * FD32_WMMeasureItem [internal]
3641 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3643 LPMEASUREITEMSTRUCT lpmeasure;
3645 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3646 lpmeasure->itemHeight = FD31_GetFldrHeight();
3647 return TRUE;
3651 /***********************************************************************
3652 * FileOpenDlgProc [internal]
3653 * Used for open and save, in fact.
3655 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3656 WPARAM wParam, LPARAM lParam)
3658 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3660 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
3661 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3663 INT_PTR lRet;
3664 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3665 if (lRet)
3666 return lRet; /* else continue message processing */
3668 switch (wMsg)
3670 case WM_INITDIALOG:
3671 return FD31_WMInitDialog(hWnd, wParam, lParam);
3673 case WM_MEASUREITEM:
3674 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3676 case WM_DRAWITEM:
3677 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3679 case WM_COMMAND:
3680 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3681 #if 0
3682 case WM_CTLCOLOR:
3683 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3684 switch (HIWORD(lParam))
3686 case CTLCOLOR_BTN:
3687 SetTextColor((HDC16)wParam, 0x00000000);
3688 return hGRAYBrush;
3689 case CTLCOLOR_STATIC:
3690 SetTextColor((HDC16)wParam, 0x00000000);
3691 return hGRAYBrush;
3693 break;
3694 #endif
3696 return FALSE;
3700 /***********************************************************************
3701 * GetFileName31A [internal]
3703 * Creates a win31 style dialog box for the user to select a file to open/save.
3705 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3706 UINT dlgType /* type dialogue : open/save */
3709 HINSTANCE hInst;
3710 BOOL bRet = FALSE;
3711 PFD31_DATA lfs;
3712 FD31_CALLBACKS callbacks;
3714 if (!lpofn || !FD31_Init()) return FALSE;
3716 TRACE("ofn flags %08lx\n", lpofn->Flags);
3717 FD32_SetupCallbacks(&callbacks);
3718 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3719 if (lfs)
3721 hInst = (HINSTANCE)GetWindowLongPtrA( lpofn->hwndOwner, GWLP_HINSTANCE );
3722 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3723 FD32_FileOpenDlgProc, (LPARAM)lfs);
3724 FD31_DestroyPrivate(lfs);
3727 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3728 return bRet;
3731 /***********************************************************************
3732 * GetFileName31W [internal]
3734 * Creates a win31 style dialog box for the user to select a file to open/save
3736 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3737 UINT dlgType /* type dialogue : open/save */
3740 HINSTANCE hInst;
3741 BOOL bRet = FALSE;
3742 PFD31_DATA lfs;
3743 FD31_CALLBACKS callbacks;
3745 if (!lpofn || !FD31_Init()) return FALSE;
3747 FD32_SetupCallbacks(&callbacks);
3748 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3749 if (lfs)
3751 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3752 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3753 FD32_FileOpenDlgProc, (LPARAM)lfs);
3754 FD31_DestroyPrivate(lfs);
3757 TRACE("file %s, file offset %d, ext offset %d\n",
3758 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3759 return bRet;
3762 /* ------------------ APIs ---------------------- */
3764 /***********************************************************************
3765 * GetOpenFileNameA (COMDLG32.@)
3767 * Creates a dialog box for the user to select a file to open.
3769 * RETURNS
3770 * TRUE on success: user enters a valid file
3771 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3774 BOOL WINAPI GetOpenFileNameA(
3775 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3777 BOOL win16look = FALSE;
3779 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3780 if (ofn->Flags & OFN_FILEMUSTEXIST)
3781 ofn->Flags |= OFN_PATHMUSTEXIST;
3783 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3784 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3786 if (win16look)
3787 return GetFileName31A(ofn, OPEN_DIALOG);
3788 else
3789 return GetFileDialog95A(ofn, OPEN_DIALOG);
3792 /***********************************************************************
3793 * GetOpenFileNameW (COMDLG32.@)
3795 * Creates a dialog box for the user to select a file to open.
3797 * RETURNS
3798 * TRUE on success: user enters a valid file
3799 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3802 BOOL WINAPI GetOpenFileNameW(
3803 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3805 BOOL win16look = FALSE;
3807 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3808 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3810 if (win16look)
3811 return GetFileName31W(ofn, OPEN_DIALOG);
3812 else
3813 return GetFileDialog95W(ofn, OPEN_DIALOG);
3817 /***********************************************************************
3818 * GetSaveFileNameA (COMDLG32.@)
3820 * Creates a dialog box for the user to select a file to save.
3822 * RETURNS
3823 * TRUE on success: user enters a valid file
3824 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3827 BOOL WINAPI GetSaveFileNameA(
3828 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3830 BOOL win16look = FALSE;
3832 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3833 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3835 if (win16look)
3836 return GetFileName31A(ofn, SAVE_DIALOG);
3837 else
3838 return GetFileDialog95A(ofn, SAVE_DIALOG);
3841 /***********************************************************************
3842 * GetSaveFileNameW (COMDLG32.@)
3844 * Creates a dialog box for the user to select a file to save.
3846 * RETURNS
3847 * TRUE on success: user enters a valid file
3848 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3851 BOOL WINAPI GetSaveFileNameW(
3852 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3854 BOOL win16look = FALSE;
3856 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3857 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3859 if (win16look)
3860 return GetFileName31W(ofn, SAVE_DIALOG);
3861 else
3862 return GetFileDialog95W(ofn, SAVE_DIALOG);