sane.ds: Add Polish translation.
[wine.git] / dlls / comdlg32 / filedlg.c
bloba3e9aa56a3b13bd79157704efa073f8cebef4b88
1 /*
2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_CREATEPROMPT, OFN_DONTADDTORECENT,
40 * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING,
41 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
42 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
44 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
49 #include "config.h"
50 #include "wine/port.h"
52 #include <ctype.h>
53 #include <stdlib.h>
54 #include <stdarg.h>
55 #include <stdio.h>
56 #include <string.h>
58 #define COBJMACROS
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
62 #include "windef.h"
63 #include "winbase.h"
64 #include "winreg.h"
65 #include "winternl.h"
66 #include "winnls.h"
67 #include "wine/unicode.h"
68 #include "wingdi.h"
69 #include "winuser.h"
70 #include "winreg.h"
71 #include "commdlg.h"
72 #include "dlgs.h"
73 #include "cdlg.h"
74 #include "filedlg31.h"
75 #include "wine/debug.h"
76 #include "cderr.h"
77 #include "shellapi.h"
78 #include "shlguid.h"
79 #include "shlobj.h"
80 #include "filedlgbrowser.h"
81 #include "shlwapi.h"
83 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
85 #define UNIMPLEMENTED_FLAGS \
86 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
87 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
88 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
89 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
91 #define IsHooked(fodInfos) \
92 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
93 /***********************************************************************
94 * Data structure and global variables
96 typedef struct SFolder
98 int m_iImageIndex; /* Index of picture in image list */
99 HIMAGELIST hImgList;
100 int m_iIndent; /* Indentation index */
101 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
103 } SFOLDER,*LPSFOLDER;
105 typedef struct tagLookInInfo
107 int iMaxIndentation;
108 UINT uSelectedItem;
109 } LookInInfos;
111 typedef struct tagFD32_PRIVATE
113 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
114 } FD32_PRIVATE, *PFD32_PRIVATE;
117 /***********************************************************************
118 * Defines and global variables
121 /* Draw item constant */
122 #define ICONWIDTH 18
123 #define XTEXTOFFSET 3
125 /* AddItem flags*/
126 #define LISTEND -1
128 /* SearchItem methods */
129 #define SEARCH_PIDL 1
130 #define SEARCH_EXP 2
131 #define ITEM_NOTFOUND -1
133 /* Undefined windows message sent by CreateViewObject*/
134 #define WM_GETISHELLBROWSER WM_USER+7
136 /* NOTE
137 * Those macros exist in windowsx.h. However, you can't really use them since
138 * they rely on the UNICODE defines and can't be used inside Wine itself.
141 /* Combo box macros */
142 #define CBAddString(hwnd,str) \
143 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
144 #define CBAddStringW(hwnd,str) \
145 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
147 #define CBInsertString(hwnd,str,pos) \
148 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
150 #define CBDeleteString(hwnd,pos) \
151 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
153 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
154 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
156 #define CBGetItemDataPtr(hwnd,iItemId) \
157 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
159 #define CBGetLBText(hwnd,iItemId,str) \
160 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
162 #define CBGetCurSel(hwnd) \
163 SendMessageA(hwnd,CB_GETCURSEL,0,0);
165 #define CBSetCurSel(hwnd,pos) \
166 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
168 #define CBGetCount(hwnd) \
169 SendMessageA(hwnd,CB_GETCOUNT,0,0);
170 #define CBShowDropDown(hwnd,show) \
171 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
172 #define CBSetItemHeight(hwnd,index,height) \
173 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
175 #define CBSetExtendedUI(hwnd,flag) \
176 SendMessageA(hwnd,CB_SETEXTENDEDUI,(WPARAM)(flag),0)
178 const char *FileOpenDlgInfosStr = "FileOpenDlgInfos"; /* windows property description string */
179 const char *LookInInfosStr = "LookInInfos"; /* LOOKIN combo box property */
181 /***********************************************************************
182 * Prototypes
185 /* Internal functions used by the dialog */
186 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
187 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
188 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
189 BOOL FILEDLG95_OnOpen(HWND hwnd);
190 static LRESULT FILEDLG95_InitControls(HWND hwnd);
191 static void FILEDLG95_Clean(HWND hwnd);
193 /* Functions used by the shell navigation */
194 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
195 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
196 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
197 static void FILEDLG95_SHELL_Clean(HWND hwnd);
198 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
200 /* Functions used by the EDIT box */
201 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator);
203 /* Functions used by the filetype combo box */
204 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
205 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
206 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
207 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
209 /* Functions used by the Look In combo box */
210 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
211 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
212 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
213 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
214 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
215 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
216 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
217 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
218 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
220 /* Miscellaneous tool functions */
221 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
222 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
223 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
224 LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
226 /* Shell memory allocation */
227 static void *MemAlloc(UINT size);
228 static void MemFree(void *mem);
230 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
231 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode);
232 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
233 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
234 static BOOL BrowseSelectedFolder(HWND hwnd);
236 /***********************************************************************
237 * GetFileName95
239 * Creates an Open common dialog box that lets the user select
240 * the drive, directory, and the name of a file or set of files to open.
242 * IN : The FileOpenDlgInfos structure associated with the dialog
243 * OUT : TRUE on success
244 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
246 static BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
249 LRESULT lRes;
250 LPCVOID template;
251 HRSRC hRes;
252 HANDLE hDlgTmpl = 0;
253 HRESULT hr;
255 /* test for missing functionality */
256 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
258 FIXME("Flags 0x%08lx not yet implemented\n",
259 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
262 /* Create the dialog from a template */
264 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
266 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
267 return FALSE;
269 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
270 !(template = LockResource( hDlgTmpl )))
272 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
273 return FALSE;
276 /* old style hook messages */
277 if (IsHooked(fodInfos))
279 fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
280 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
281 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
282 fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
285 /* Some shell namespace extensions depend on COM being initialized. */
286 hr = OleInitialize(NULL);
288 if (fodInfos->unicode)
289 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
290 template,
291 fodInfos->ofnInfos->hwndOwner,
292 FileOpenDlgProc95,
293 (LPARAM) fodInfos);
294 else
295 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
296 (LPCDLGTEMPLATEA) template,
297 fodInfos->ofnInfos->hwndOwner,
298 FileOpenDlgProc95,
299 (LPARAM) fodInfos);
300 if (SUCCEEDED(hr))
301 OleUninitialize();
303 /* Unable to create the dialog */
304 if( lRes == -1)
305 return FALSE;
307 return lRes;
310 /***********************************************************************
311 * GetFileDialog95A
313 * Call GetFileName95 with this structure and clean the memory.
315 * IN : The OPENFILENAMEA initialisation structure passed to
316 * GetOpenFileNameA win api function (see filedlg.c)
318 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
320 BOOL ret;
321 FileOpenDlgInfos fodInfos;
322 LPSTR lpstrSavDir = NULL;
323 LPWSTR title = NULL;
324 LPWSTR defext = NULL;
325 LPWSTR filter = NULL;
326 LPWSTR customfilter = NULL;
328 /* Initialize FileOpenDlgInfos structure */
329 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
331 /* Pass in the original ofn */
332 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
334 /* save current directory */
335 if (ofn->Flags & OFN_NOCHANGEDIR)
337 lpstrSavDir = MemAlloc(MAX_PATH);
338 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
341 fodInfos.unicode = FALSE;
343 /* convert all the input strings to unicode */
344 if(ofn->lpstrInitialDir)
346 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
347 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
348 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
350 else
351 fodInfos.initdir = NULL;
353 if(ofn->lpstrFile)
355 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
356 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
358 else
359 fodInfos.filename = NULL;
361 if(ofn->lpstrDefExt)
363 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
364 defext = MemAlloc((len+1)*sizeof(WCHAR));
365 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
367 fodInfos.defext = defext;
369 if(ofn->lpstrTitle)
371 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
372 title = MemAlloc((len+1)*sizeof(WCHAR));
373 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
375 fodInfos.title = title;
377 if (ofn->lpstrFilter)
379 LPCSTR s;
380 int n, len;
382 /* filter is a list... title\0ext\0......\0\0 */
383 s = ofn->lpstrFilter;
384 while (*s) s = s+strlen(s)+1;
385 s++;
386 n = s - ofn->lpstrFilter;
387 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
388 filter = MemAlloc(len*sizeof(WCHAR));
389 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
391 fodInfos.filter = filter;
393 /* convert lpstrCustomFilter */
394 if (ofn->lpstrCustomFilter)
396 LPCSTR s;
397 int n, len;
399 /* customfilter contains a pair of strings... title\0ext\0 */
400 s = ofn->lpstrCustomFilter;
401 if (*s) s = s+strlen(s)+1;
402 if (*s) s = s+strlen(s)+1;
403 n = s - ofn->lpstrCustomFilter;
404 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
405 customfilter = MemAlloc(len*sizeof(WCHAR));
406 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
408 fodInfos.customfilter = customfilter;
410 /* Initialize the dialog property */
411 fodInfos.DlgInfos.dwDlgProp = 0;
412 fodInfos.DlgInfos.hwndCustomDlg = NULL;
414 switch(iDlgType)
416 case OPEN_DIALOG :
417 ret = GetFileName95(&fodInfos);
418 break;
419 case SAVE_DIALOG :
420 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
421 ret = GetFileName95(&fodInfos);
422 break;
423 default :
424 ret = 0;
427 if (lpstrSavDir)
429 SetCurrentDirectoryA(lpstrSavDir);
430 MemFree(lpstrSavDir);
433 MemFree(title);
434 MemFree(defext);
435 MemFree(filter);
436 MemFree(customfilter);
437 MemFree(fodInfos.initdir);
438 MemFree(fodInfos.filename);
440 TRACE("selected file: %s\n",ofn->lpstrFile);
442 return ret;
445 /***********************************************************************
446 * GetFileDialog95W
448 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
449 * Call GetFileName95 with this structure and clean the memory.
452 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
454 BOOL ret;
455 FileOpenDlgInfos fodInfos;
456 LPWSTR lpstrSavDir = NULL;
458 /* Initialize FileOpenDlgInfos structure */
459 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
461 /* Pass in the original ofn */
462 fodInfos.ofnInfos = ofn;
464 fodInfos.title = ofn->lpstrTitle;
465 fodInfos.defext = ofn->lpstrDefExt;
466 fodInfos.filter = ofn->lpstrFilter;
467 fodInfos.customfilter = ofn->lpstrCustomFilter;
469 /* convert string arguments, save others */
470 if(ofn->lpstrFile)
472 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
473 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
475 else
476 fodInfos.filename = NULL;
478 if(ofn->lpstrInitialDir)
480 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
481 DWORD len = strlenW(ofn->lpstrInitialDir)+1;
482 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
483 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
485 else
486 fodInfos.initdir = NULL;
488 /* save current directory */
489 if (ofn->Flags & OFN_NOCHANGEDIR)
491 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
492 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
495 fodInfos.unicode = TRUE;
497 switch(iDlgType)
499 case OPEN_DIALOG :
500 ret = GetFileName95(&fodInfos);
501 break;
502 case SAVE_DIALOG :
503 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
504 ret = GetFileName95(&fodInfos);
505 break;
506 default :
507 ret = 0;
510 if (lpstrSavDir)
512 SetCurrentDirectoryW(lpstrSavDir);
513 MemFree(lpstrSavDir);
516 /* restore saved IN arguments and convert OUT arguments back */
517 MemFree(fodInfos.filename);
518 MemFree(fodInfos.initdir);
519 return ret;
522 /******************************************************************************
523 * COMDLG32_GetDisplayNameOf [internal]
525 * Helper function to get the display name for a pidl.
527 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
528 LPSHELLFOLDER psfDesktop;
529 STRRET strret;
531 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
532 return FALSE;
534 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
535 IShellFolder_Release(psfDesktop);
536 return FALSE;
539 IShellFolder_Release(psfDesktop);
540 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
543 /***********************************************************************
544 * ArrangeCtrlPositions [internal]
546 * NOTE: Do not change anything here without a lot of testing.
548 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
550 HWND hwndChild, hwndStc32;
551 RECT rectParent, rectChild, rectStc32;
552 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
554 /* Take into account if open as read only checkbox and help button
555 * are hidden
557 if (hide_help)
559 RECT rectHelp, rectCancel;
560 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
561 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
562 /* subtract the height of the help button plus the space between
563 * the help button and the cancel button to the height of the dialog
565 help_fixup = rectHelp.bottom - rectCancel.bottom;
569 There are two possibilities to add components to the default file dialog box.
571 By default, all the new components are added below the standard dialog box (the else case).
573 However, if there is a static text component with the stc32 id, a special case happens.
574 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
575 in the window and the cx and cy indicate how to size the window.
576 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
577 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
581 GetClientRect(hwndParentDlg, &rectParent);
583 /* when arranging controls we have to use fixed parent size */
584 rectParent.bottom -= help_fixup;
586 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
587 if (hwndStc32)
589 GetWindowRect(hwndStc32, &rectStc32);
590 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
592 /* set the size of the stc32 control according to the size of
593 * client area of the parent dialog
595 SetWindowPos(hwndStc32, 0,
596 0, 0,
597 rectParent.right, rectParent.bottom,
598 SWP_NOMOVE | SWP_NOZORDER);
600 else
601 SetRectEmpty(&rectStc32);
603 /* this part moves controls of the child dialog */
604 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
605 while (hwndChild)
607 if (hwndChild != hwndStc32)
609 GetWindowRect(hwndChild, &rectChild);
610 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
612 /* move only if stc32 exist */
613 if (hwndStc32 && rectChild.left > rectStc32.right)
615 LONG old_left = rectChild.left;
617 /* move to the right of visible controls of the parent dialog */
618 rectChild.left += rectParent.right;
619 rectChild.left -= rectStc32.right;
621 child_width_fixup = rectChild.left - old_left;
623 /* move even if stc32 doesn't exist */
624 if (rectChild.top >= rectStc32.bottom)
626 LONG old_top = rectChild.top;
628 /* move below visible controls of the parent dialog */
629 rectChild.top += rectParent.bottom;
630 rectChild.top -= rectStc32.bottom - rectStc32.top;
632 child_height_fixup = rectChild.top - old_top;
635 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
636 0, 0, SWP_NOSIZE | SWP_NOZORDER);
638 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
641 /* this part moves controls of the parent dialog */
642 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
643 while (hwndChild)
645 if (hwndChild != hwndChildDlg)
647 GetWindowRect(hwndChild, &rectChild);
648 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
650 /* left,top of stc32 marks the position of controls
651 * from the parent dialog
653 rectChild.left += rectStc32.left;
654 rectChild.top += rectStc32.top;
656 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
657 0, 0, SWP_NOSIZE | SWP_NOZORDER);
659 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
662 /* calculate the size of the resulting dialog */
664 /* here we have to use original parent size */
665 GetClientRect(hwndParentDlg, &rectParent);
666 GetClientRect(hwndChildDlg, &rectChild);
668 if (hwndStc32)
670 rectChild.right += child_width_fixup;
671 rectChild.bottom += child_height_fixup;
673 if (rectParent.right > rectChild.right)
675 rectParent.right += rectChild.right;
676 rectParent.right -= rectStc32.right - rectStc32.left;
678 else
680 rectParent.right = rectChild.right;
683 if (rectParent.bottom > rectChild.bottom)
685 rectParent.bottom += rectChild.bottom;
686 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
688 else
690 /* child dialog is higher, unconditionally set new dialog
691 * height to its size (help_fixup will be subtracted below)
693 rectParent.bottom = rectChild.bottom + help_fixup;
696 else
698 rectParent.bottom += rectChild.bottom;
701 /* finally use fixed parent size */
702 rectParent.bottom -= help_fixup;
704 /* set the size of the parent dialog */
705 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
706 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
707 SetWindowPos(hwndParentDlg, 0,
708 0, 0,
709 rectParent.right - rectParent.left,
710 rectParent.bottom - rectParent.top,
711 SWP_NOMOVE | SWP_NOZORDER);
714 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
716 switch(uMsg) {
717 case WM_INITDIALOG:
718 return TRUE;
720 return FALSE;
723 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
725 LPCVOID template;
726 HRSRC hRes;
727 HANDLE hDlgTmpl = 0;
728 HWND hChildDlg = 0;
730 TRACE("\n");
733 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
734 * structure's hInstance parameter is not a HINSTANCE, but
735 * instead a pointer to a template resource to use.
737 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
739 HINSTANCE hinst;
740 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
742 hinst = COMDLG32_hInstance;
743 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
745 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
746 return NULL;
749 else
751 hinst = fodInfos->ofnInfos->hInstance;
752 if(fodInfos->unicode)
754 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
755 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
757 else
759 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
760 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
762 if (!hRes)
764 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
765 return NULL;
767 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
768 !(template = LockResource( hDlgTmpl )))
770 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
771 return NULL;
774 if (fodInfos->unicode)
775 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
776 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
777 (LPARAM)fodInfos->ofnInfos);
778 else
779 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
780 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
781 (LPARAM)fodInfos->ofnInfos);
782 if(hChildDlg)
784 ShowWindow(hChildDlg,SW_SHOW);
785 return hChildDlg;
788 else if( IsHooked(fodInfos))
790 RECT rectHwnd;
791 struct {
792 DLGTEMPLATE tmplate;
793 WORD menu,class,title;
794 } temp;
795 GetClientRect(hwnd,&rectHwnd);
796 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
797 temp.tmplate.dwExtendedStyle = 0;
798 temp.tmplate.cdit = 0;
799 temp.tmplate.x = 0;
800 temp.tmplate.y = 0;
801 temp.tmplate.cx = 0;
802 temp.tmplate.cy = 0;
803 temp.menu = temp.class = temp.title = 0;
805 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
806 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
808 return hChildDlg;
810 return NULL;
813 /***********************************************************************
814 * SendCustomDlgNotificationMessage
816 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
819 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
821 LRESULT hook_result = 0;
823 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
825 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
827 if(!fodInfos) return 0;
829 if(fodInfos->DlgInfos.hwndCustomDlg)
831 TRACE("CALL NOTIFY for %x\n", uCode);
832 if(fodInfos->unicode)
834 OFNOTIFYW ofnNotify;
835 ofnNotify.hdr.hwndFrom=hwndParentDlg;
836 ofnNotify.hdr.idFrom=0;
837 ofnNotify.hdr.code = uCode;
838 ofnNotify.lpOFN = fodInfos->ofnInfos;
839 ofnNotify.pszFile = NULL;
840 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
842 else
844 OFNOTIFYA ofnNotify;
845 ofnNotify.hdr.hwndFrom=hwndParentDlg;
846 ofnNotify.hdr.idFrom=0;
847 ofnNotify.hdr.code = uCode;
848 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
849 ofnNotify.pszFile = NULL;
850 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
852 TRACE("RET NOTIFY\n");
854 TRACE("Retval: 0x%08lx\n", hook_result);
855 return hook_result;
858 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer)
860 UINT sizeUsed = 0, n, total;
861 LPWSTR lpstrFileList = NULL;
862 WCHAR lpstrCurrentDir[MAX_PATH];
863 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
865 TRACE("CDM_GETFILEPATH:\n");
867 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
868 return -1;
870 /* get path and filenames */
871 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrCurrentDir);
872 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
874 TRACE("path >%s< filespec >%s< %d files\n",
875 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
877 if( fodInfos->unicode )
879 LPWSTR bufW = buffer;
880 total = strlenW(lpstrCurrentDir) + 1 + sizeUsed;
882 /* Prepend the current path */
883 n = strlenW(lpstrCurrentDir) + 1;
884 memcpy( bufW, lpstrCurrentDir, min(n,size) * sizeof(WCHAR));
885 if(n<size)
887 /* 'n' includes trailing \0 */
888 bufW[n-1] = '\\';
889 memcpy( &bufW[n], lpstrFileList, (size-n)*sizeof(WCHAR) );
891 TRACE("returned -> %s\n",debugstr_wn(bufW, total));
893 else
895 LPSTR bufA = buffer;
896 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
897 NULL, 0, NULL, NULL);
898 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
899 NULL, 0, NULL, NULL);
901 /* Prepend the current path */
902 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
903 bufA, size, NULL, NULL);
905 if(n<size)
907 /* 'n' includes trailing \0 */
908 bufA[n-1] = '\\';
909 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
910 &bufA[n], size-n, NULL, NULL);
913 TRACE("returned -> %s\n",debugstr_an(bufA, total));
915 MemFree(lpstrFileList);
917 return total;
920 static INT_PTR FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer)
922 UINT sizeUsed = 0;
923 LPWSTR lpstrFileList = NULL;
924 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
926 TRACE("CDM_GETSPEC:\n");
928 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
929 if( fodInfos->unicode )
931 LPWSTR bufW = buffer;
932 memcpy( bufW, lpstrFileList, sizeof(WCHAR)*sizeUsed );
934 else
936 LPSTR bufA = buffer;
937 sizeUsed = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed,
938 NULL, 0, NULL, NULL);
939 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
940 bufA, size, NULL, NULL);
942 MemFree(lpstrFileList);
944 return sizeUsed;
947 /***********************************************************************
948 * FILEDLG95_HandleCustomDialogMessages
950 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
952 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
954 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
955 WCHAR lpstrPath[MAX_PATH];
956 INT_PTR retval;
958 if(!fodInfos) return FALSE;
960 switch(uMsg)
962 case CDM_GETFILEPATH:
963 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
964 break;
966 case CDM_GETFOLDERPATH:
967 TRACE("CDM_GETFOLDERPATH:\n");
968 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
969 if (lParam)
971 if (fodInfos->unicode)
972 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
973 else
974 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
975 (LPSTR)lParam, (int)wParam, NULL, NULL);
977 retval = strlenW(lpstrPath);
978 break;
980 case CDM_GETSPEC:
981 retval = FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
982 break;
984 case CDM_SETCONTROLTEXT:
985 TRACE("CDM_SETCONTROLTEXT:\n");
986 if ( lParam )
988 if( fodInfos->unicode )
989 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
990 else
991 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
993 retval = TRUE;
994 break;
996 case CDM_HIDECONTROL:
997 /* MSDN states that it should fail for not OFN_EXPLORER case */
998 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1000 HWND control = GetDlgItem( hwnd, wParam );
1001 if (control) ShowWindow( control, SW_HIDE );
1002 retval = TRUE;
1004 else retval = FALSE;
1005 break;
1007 default:
1008 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1009 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1010 return FALSE;
1012 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1013 return TRUE;
1016 /***********************************************************************
1017 * FileOpenDlgProc95
1019 * File open dialog procedure
1021 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1023 #if 0
1024 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
1025 #endif
1027 switch(uMsg)
1029 case WM_INITDIALOG:
1031 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1033 /* Adds the FileOpenDlgInfos in the property list of the dialog
1034 so it will be easily accessible through a GetPropA(...) */
1035 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
1037 fodInfos->DlgInfos.hwndCustomDlg =
1038 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1040 FILEDLG95_InitControls(hwnd);
1042 if (fodInfos->DlgInfos.hwndCustomDlg)
1044 RECT rc;
1045 UINT flags = SWP_NOACTIVATE;
1047 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1048 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1050 /* resize the custom dialog to the parent size */
1051 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1052 GetClientRect(hwnd, &rc);
1053 else
1055 /* our own fake template is zero sized and doesn't have
1056 * children, so there is no need to resize it.
1057 * Picasa depends on it.
1059 flags |= SWP_NOSIZE;
1060 SetRectEmpty(&rc);
1062 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1063 0, 0, rc.right, rc.bottom, flags);
1066 FILEDLG95_FillControls(hwnd, wParam, lParam);
1068 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1069 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1070 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1071 return 0;
1073 case WM_COMMAND:
1074 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1075 case WM_DRAWITEM:
1077 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1079 case IDC_LOOKIN:
1080 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1081 return TRUE;
1084 return FALSE;
1086 case WM_GETISHELLBROWSER:
1087 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1089 case WM_DESTROY:
1090 RemovePropA(hwnd, FileOpenDlgInfosStr);
1091 return FALSE;
1093 case WM_NOTIFY:
1095 LPNMHDR lpnmh = (LPNMHDR)lParam;
1096 UINT stringId = -1;
1098 /* set up the button tooltips strings */
1099 if(TTN_GETDISPINFOA == lpnmh->code )
1101 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1102 switch(lpnmh->idFrom )
1104 /* Up folder button */
1105 case FCIDM_TB_UPFOLDER:
1106 stringId = IDS_UPFOLDER;
1107 break;
1108 /* New folder button */
1109 case FCIDM_TB_NEWFOLDER:
1110 stringId = IDS_NEWFOLDER;
1111 break;
1112 /* List option button */
1113 case FCIDM_TB_SMALLICON:
1114 stringId = IDS_LISTVIEW;
1115 break;
1116 /* Details option button */
1117 case FCIDM_TB_REPORTVIEW:
1118 stringId = IDS_REPORTVIEW;
1119 break;
1120 /* Desktop button */
1121 case FCIDM_TB_DESKTOP:
1122 stringId = IDS_TODESKTOP;
1123 break;
1124 default:
1125 stringId = 0;
1127 lpdi->hinst = COMDLG32_hInstance;
1128 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1130 return FALSE;
1132 default :
1133 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1134 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1135 return FALSE;
1139 /***********************************************************************
1140 * FILEDLG95_InitControls
1142 * WM_INITDIALOG message handler (before hook notification)
1144 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1146 int win2000plus = 0;
1147 int win98plus = 0;
1148 int handledPath = FALSE;
1149 OSVERSIONINFOA osVi;
1150 static const WCHAR szwSlash[] = { '\\', 0 };
1151 static const WCHAR szwStar[] = { '*',0 };
1153 TBBUTTON tbb[] =
1155 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1156 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1157 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1158 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1159 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1160 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1161 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1162 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1163 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1165 TBADDBITMAP tba[2];
1166 RECT rectTB;
1167 RECT rectlook;
1168 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1170 tba[0].hInst = HINST_COMMCTRL;
1171 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1172 tba[1].hInst = COMDLG32_hInstance;
1173 tba[1].nID = 800;
1175 TRACE("%p\n", fodInfos);
1177 /* Get windows version emulating */
1178 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1179 GetVersionExA(&osVi);
1180 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1181 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1182 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1183 win2000plus = (osVi.dwMajorVersion > 4);
1184 if (win2000plus) win98plus = TRUE;
1186 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1188 /* Get the hwnd of the controls */
1189 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1190 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1191 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1193 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1194 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1196 /* construct the toolbar */
1197 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1198 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1200 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1201 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1202 rectTB.left = rectlook.right;
1203 rectTB.top = rectlook.top-1;
1205 if (fodInfos->unicode)
1206 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1207 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1208 rectTB.left, rectTB.top,
1209 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1210 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1211 else
1212 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1213 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1214 rectTB.left, rectTB.top,
1215 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1216 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1218 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1220 /* FIXME: use TB_LOADIMAGES when implemented */
1221 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1222 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1223 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1225 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1226 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1228 /* Set the window text with the text specified in the OPENFILENAME structure */
1229 if(fodInfos->title)
1231 SetWindowTextW(hwnd,fodInfos->title);
1233 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1235 WCHAR buf[16];
1236 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1237 SetWindowTextW(hwnd, buf);
1240 /* Initialise the file name edit control */
1241 handledPath = FALSE;
1242 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1244 if(fodInfos->filename)
1246 /* 1. If win2000 or higher and filename contains a path, use it
1247 in preference over the lpstrInitialDir */
1248 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1249 WCHAR tmpBuf[MAX_PATH];
1250 WCHAR *nameBit;
1251 DWORD result;
1253 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1254 if (result) {
1256 /* nameBit is always shorter than the original filename */
1257 strcpyW(fodInfos->filename,nameBit);
1259 *nameBit = 0x00;
1260 if (fodInfos->initdir == NULL)
1261 MemFree(fodInfos->initdir);
1262 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1263 strcpyW(fodInfos->initdir, tmpBuf);
1264 handledPath = TRUE;
1265 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1266 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1268 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1270 } else {
1271 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1275 /* 2. (All platforms) If initdir is not null, then use it */
1276 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1277 (*fodInfos->initdir!=0x00))
1279 /* Work out the proper path as supplied one might be relative */
1280 /* (Here because supplying '.' as dir browses to My Computer) */
1281 if (handledPath==FALSE) {
1282 WCHAR tmpBuf[MAX_PATH];
1283 WCHAR tmpBuf2[MAX_PATH];
1284 WCHAR *nameBit;
1285 DWORD result;
1287 strcpyW(tmpBuf, fodInfos->initdir);
1288 if( PathFileExistsW(tmpBuf) ) {
1289 /* initdir does not have to be a directory. If a file is
1290 * specified, the dir part is taken */
1291 if( PathIsDirectoryW(tmpBuf)) {
1292 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1293 strcatW(tmpBuf, szwSlash);
1295 strcatW(tmpBuf, szwStar);
1297 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1298 if (result) {
1299 *nameBit = 0x00;
1300 MemFree(fodInfos->initdir);
1301 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1302 strcpyW(fodInfos->initdir, tmpBuf2);
1303 handledPath = TRUE;
1304 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1307 else if (fodInfos->initdir)
1309 MemFree(fodInfos->initdir);
1310 fodInfos->initdir = NULL;
1311 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1316 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1317 (*fodInfos->initdir==0x00)))
1319 /* 3. All except w2k+: if filename contains a path use it */
1320 if (!win2000plus && fodInfos->filename &&
1321 *fodInfos->filename &&
1322 strpbrkW(fodInfos->filename, szwSlash)) {
1323 WCHAR tmpBuf[MAX_PATH];
1324 WCHAR *nameBit;
1325 DWORD result;
1327 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1328 tmpBuf, &nameBit);
1329 if (result) {
1330 int len;
1332 /* nameBit is always shorter than the original filename */
1333 strcpyW(fodInfos->filename, nameBit);
1334 *nameBit = 0x00;
1336 len = strlenW(tmpBuf);
1337 MemFree(fodInfos->initdir);
1338 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1339 strcpyW(fodInfos->initdir, tmpBuf);
1341 handledPath = TRUE;
1342 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1343 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1345 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1348 /* 4. win98+ and win2000+ if any files of specified filter types in
1349 current directory, use it */
1350 if ( win98plus && handledPath == FALSE &&
1351 fodInfos->filter && *fodInfos->filter) {
1353 BOOL searchMore = TRUE;
1354 LPCWSTR lpstrPos = fodInfos->filter;
1355 WIN32_FIND_DATAW FindFileData;
1356 HANDLE hFind;
1358 while (searchMore)
1360 /* filter is a list... title\0ext\0......\0\0 */
1362 /* Skip the title */
1363 if(! *lpstrPos) break; /* end */
1364 lpstrPos += strlenW(lpstrPos) + 1;
1366 /* See if any files exist in the current dir with this extension */
1367 if(! *lpstrPos) break; /* end */
1369 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1371 if (hFind == INVALID_HANDLE_VALUE) {
1372 /* None found - continue search */
1373 lpstrPos += strlenW(lpstrPos) + 1;
1375 } else {
1376 searchMore = FALSE;
1378 MemFree(fodInfos->initdir);
1379 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1380 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1382 handledPath = TRUE;
1383 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1384 debugstr_w(lpstrPos));
1385 break;
1390 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1392 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1393 if (handledPath == FALSE && (win2000plus || win98plus)) {
1394 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1396 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1398 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1400 /* last fallback */
1401 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1402 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1403 } else {
1404 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1406 } else {
1407 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1409 handledPath = TRUE;
1410 } else if (handledPath==FALSE) {
1411 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1412 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1413 handledPath = TRUE;
1414 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1417 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1418 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1420 /* Must the open as read only check box be checked ?*/
1421 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1423 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1426 /* Must the open as read only check box be hidden? */
1427 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1429 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1430 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1433 /* Must the help button be hidden? */
1434 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1436 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1437 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1440 /* Resize the height, if open as read only checkbox ad help button
1441 are hidden and we are not using a custom template nor a customDialog
1443 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1444 (!(fodInfos->ofnInfos->Flags &
1445 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1446 (!fodInfos->DlgInfos.hwndCustomDlg ))
1448 RECT rectDlg, rectHelp, rectCancel;
1449 GetWindowRect(hwnd, &rectDlg);
1450 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1451 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1452 /* subtract the height of the help button plus the space between
1453 the help button and the cancel button to the height of the dialog */
1454 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1455 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1456 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1458 /* change Open to Save */
1459 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1461 WCHAR buf[16];
1462 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1463 SetDlgItemTextW(hwnd, IDOK, buf);
1464 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1465 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1467 return 0;
1470 /***********************************************************************
1471 * FILEDLG95_FillControls
1473 * WM_INITDIALOG message handler (after hook notification)
1475 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1477 LPITEMIDLIST pidlItemId = NULL;
1479 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1481 TRACE("dir=%s file=%s\n",
1482 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1484 /* Get the initial directory pidl */
1486 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1488 WCHAR path[MAX_PATH];
1490 GetCurrentDirectoryW(MAX_PATH,path);
1491 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1494 /* Initialise shell objects */
1495 FILEDLG95_SHELL_Init(hwnd);
1497 /* Initialize the Look In combo box */
1498 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1500 /* Initialize the filter combo box */
1501 FILEDLG95_FILETYPE_Init(hwnd);
1503 /* Browse to the initial directory */
1504 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1506 /* Free pidlItem memory */
1507 COMDLG32_SHFree(pidlItemId);
1509 return TRUE;
1511 /***********************************************************************
1512 * FILEDLG95_Clean
1514 * Regroups all the cleaning functions of the filedlg
1516 void FILEDLG95_Clean(HWND hwnd)
1518 FILEDLG95_FILETYPE_Clean(hwnd);
1519 FILEDLG95_LOOKIN_Clean(hwnd);
1520 FILEDLG95_SHELL_Clean(hwnd);
1522 /***********************************************************************
1523 * FILEDLG95_OnWMCommand
1525 * WM_COMMAND message handler
1527 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1529 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1530 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1531 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1533 switch(wID)
1535 /* OK button */
1536 case IDOK:
1537 FILEDLG95_OnOpen(hwnd);
1538 break;
1539 /* Cancel button */
1540 case IDCANCEL:
1541 FILEDLG95_Clean(hwnd);
1542 EndDialog(hwnd, FALSE);
1543 break;
1544 /* Filetype combo box */
1545 case IDC_FILETYPE:
1546 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1547 break;
1548 /* LookIn combo box */
1549 case IDC_LOOKIN:
1550 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1551 break;
1553 /* --- toolbar --- */
1554 /* Up folder button */
1555 case FCIDM_TB_UPFOLDER:
1556 FILEDLG95_SHELL_UpFolder(hwnd);
1557 break;
1558 /* New folder button */
1559 case FCIDM_TB_NEWFOLDER:
1560 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1561 break;
1562 /* List option button */
1563 case FCIDM_TB_SMALLICON:
1564 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1565 break;
1566 /* Details option button */
1567 case FCIDM_TB_REPORTVIEW:
1568 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1569 break;
1570 /* Details option button */
1571 case FCIDM_TB_DESKTOP:
1572 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1573 break;
1575 case IDC_FILENAME:
1576 break;
1579 /* Do not use the listview selection anymore */
1580 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1581 return 0;
1584 /***********************************************************************
1585 * FILEDLG95_OnWMGetIShellBrowser
1587 * WM_GETISHELLBROWSER message handler
1589 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1592 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1594 TRACE("\n");
1596 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1598 return TRUE;
1602 /***********************************************************************
1603 * FILEDLG95_SendFileOK
1605 * Sends the CDN_FILEOK notification if required
1607 * RETURNS
1608 * TRUE if the dialog should close
1609 * FALSE if the dialog should not be closed
1611 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1613 /* ask the hook if we can close */
1614 if(IsHooked(fodInfos))
1616 LRESULT retval;
1618 TRACE("---\n");
1619 /* First send CDN_FILEOK as MSDN doc says */
1620 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1621 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1623 TRACE("canceled\n");
1624 return (retval == 0);
1627 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1628 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1629 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1630 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1632 TRACE("canceled\n");
1633 return (retval == 0);
1636 return TRUE;
1639 /***********************************************************************
1640 * FILEDLG95_OnOpenMultipleFiles
1642 * Handles the opening of multiple files.
1644 * FIXME
1645 * check destination buffer size
1647 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1649 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1650 UINT nCount, nSizePath;
1651 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1653 TRACE("\n");
1655 if(fodInfos->unicode)
1657 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1658 ofn->lpstrFile[0] = '\0';
1660 else
1662 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1663 ofn->lpstrFile[0] = '\0';
1666 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1668 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1669 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1670 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1672 LPWSTR lpstrTemp = lpstrFileList;
1674 for ( nCount = 0; nCount < nFileCount; nCount++ )
1676 LPITEMIDLIST pidl;
1678 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1679 if (!pidl)
1681 WCHAR lpstrNotFound[100];
1682 WCHAR lpstrMsg[100];
1683 WCHAR tmp[400];
1684 static const WCHAR nl[] = {'\n',0};
1686 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1687 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1689 strcpyW(tmp, lpstrTemp);
1690 strcatW(tmp, nl);
1691 strcatW(tmp, lpstrNotFound);
1692 strcatW(tmp, nl);
1693 strcatW(tmp, lpstrMsg);
1695 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1696 return FALSE;
1699 /* move to the next file in the list of files */
1700 lpstrTemp += strlenW(lpstrTemp) + 1;
1701 COMDLG32_SHFree(pidl);
1705 nSizePath = strlenW(lpstrPathSpec) + 1;
1706 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1708 /* For "oldstyle" dialog the components have to
1709 be separated by blanks (not '\0'!) and short
1710 filenames have to be used! */
1711 FIXME("Components have to be separated by blanks\n");
1713 if(fodInfos->unicode)
1715 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1716 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1717 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1719 else
1721 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1723 if (ofn->lpstrFile != NULL)
1725 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1726 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1727 if (ofn->nMaxFile > nSizePath)
1729 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1730 ofn->lpstrFile + nSizePath,
1731 ofn->nMaxFile - nSizePath, NULL, NULL);
1736 fodInfos->ofnInfos->nFileOffset = nSizePath;
1737 fodInfos->ofnInfos->nFileExtension = 0;
1739 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1740 return FALSE;
1742 /* clean and exit */
1743 FILEDLG95_Clean(hwnd);
1744 return EndDialog(hwnd,TRUE);
1747 /***********************************************************************
1748 * FILEDLG95_OnOpen
1750 * Ok button WM_COMMAND message handler
1752 * If the function succeeds, the return value is nonzero.
1754 #define ONOPEN_BROWSE 1
1755 #define ONOPEN_OPEN 2
1756 #define ONOPEN_SEARCH 3
1757 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1759 WCHAR strMsgTitle[MAX_PATH];
1760 WCHAR strMsgText [MAX_PATH];
1761 if (idCaption)
1762 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1763 else
1764 strMsgTitle[0] = '\0';
1765 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1766 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1769 BOOL FILEDLG95_OnOpen(HWND hwnd)
1771 LPWSTR lpstrFileList;
1772 UINT nFileCount = 0;
1773 UINT sizeUsed = 0;
1774 BOOL ret = TRUE;
1775 WCHAR lpstrPathAndFile[MAX_PATH];
1776 WCHAR lpstrTemp[MAX_PATH];
1777 LPSHELLFOLDER lpsf = NULL;
1778 int nOpenAction;
1779 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1781 TRACE("hwnd=%p\n", hwnd);
1783 /* get the files from the edit control */
1784 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1786 /* try if the user selected a folder in the shellview */
1787 if(nFileCount == 0)
1789 BrowseSelectedFolder(hwnd);
1790 return FALSE;
1793 if(nFileCount > 1)
1795 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1796 goto ret;
1799 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1802 Step 1: Build a complete path name from the current folder and
1803 the filename or path in the edit box.
1804 Special cases:
1805 - the path in the edit box is a root path
1806 (with or without drive letter)
1807 - the edit box contains ".." (or a path with ".." in it)
1810 /* Get the current directory name */
1811 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1813 /* last fallback */
1814 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1816 PathAddBackslashW(lpstrPathAndFile);
1818 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1820 /* if the user specifyed a fully qualified path use it */
1821 if(PathIsRelativeW(lpstrFileList))
1823 strcatW(lpstrPathAndFile, lpstrFileList);
1825 else
1827 /* does the path have a drive letter? */
1828 if (PathGetDriveNumberW(lpstrFileList) == -1)
1829 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1830 else
1831 strcpyW(lpstrPathAndFile, lpstrFileList);
1834 /* resolve "." and ".." */
1835 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1836 strcpyW(lpstrPathAndFile, lpstrTemp);
1837 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1839 MemFree(lpstrFileList);
1842 Step 2: here we have a cleaned up path
1844 We have to parse the path step by step to see if we have to browse
1845 to a folder if the path points to a directory or the last
1846 valid element is a directory.
1848 valid variables:
1849 lpstrPathAndFile: cleaned up path
1852 if (nFileCount &&
1853 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1854 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1855 nOpenAction = ONOPEN_OPEN;
1856 else
1857 nOpenAction = ONOPEN_BROWSE;
1859 /* don't apply any checks with OFN_NOVALIDATE */
1861 LPWSTR lpszTemp, lpszTemp1;
1862 LPITEMIDLIST pidl = NULL;
1863 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1865 /* check for invalid chars */
1866 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1868 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1869 ret = FALSE;
1870 goto ret;
1873 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1875 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1876 while (lpszTemp1)
1878 LPSHELLFOLDER lpsfChild;
1879 WCHAR lpwstrTemp[MAX_PATH];
1880 DWORD dwEaten, dwAttributes;
1881 LPWSTR p;
1883 strcpyW(lpwstrTemp, lpszTemp);
1884 p = PathFindNextComponentW(lpwstrTemp);
1886 if (!p) break; /* end of path */
1888 *p = 0;
1889 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1891 /* There are no wildcards when OFN_NOVALIDATE is set */
1892 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1894 static const WCHAR wszWild[] = { '*', '?', 0 };
1895 /* if the last element is a wildcard do a search */
1896 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1898 nOpenAction = ONOPEN_SEARCH;
1899 break;
1902 lpszTemp1 = lpszTemp;
1904 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1906 /* append a backslash to drive letters */
1907 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1908 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1909 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1911 PathAddBackslashW(lpwstrTemp);
1914 dwAttributes = SFGAO_FOLDER;
1915 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1917 /* the path component is valid, we have a pidl of the next path component */
1918 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1919 if(dwAttributes & SFGAO_FOLDER)
1921 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1923 ERR("bind to failed\n"); /* should not fail */
1924 break;
1926 IShellFolder_Release(lpsf);
1927 lpsf = lpsfChild;
1928 lpsfChild = NULL;
1930 else
1932 TRACE("value\n");
1934 /* end dialog, return value */
1935 nOpenAction = ONOPEN_OPEN;
1936 break;
1938 COMDLG32_SHFree(pidl);
1939 pidl = NULL;
1941 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1943 if(*lpszTemp) /* points to trailing null for last path element */
1945 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1947 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1948 break;
1951 else
1953 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1954 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1956 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1957 break;
1960 /* change to the current folder */
1961 nOpenAction = ONOPEN_OPEN;
1962 break;
1964 else
1966 nOpenAction = ONOPEN_OPEN;
1967 break;
1970 if(pidl) COMDLG32_SHFree(pidl);
1974 Step 3: here we have a cleaned up and validated path
1976 valid variables:
1977 lpsf: ShellFolder bound to the rightmost valid path component
1978 lpstrPathAndFile: cleaned up path
1979 nOpenAction: action to do
1981 TRACE("end validate sf=%p\n", lpsf);
1983 switch(nOpenAction)
1985 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1986 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1988 int iPos;
1989 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1990 DWORD len;
1992 /* replace the current filter */
1993 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1994 len = strlenW(lpszTemp)+1;
1995 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1996 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1998 /* set the filter cb to the extension when possible */
1999 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2000 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2002 /* fall through */
2003 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2004 TRACE("ONOPEN_BROWSE\n");
2006 IPersistFolder2 * ppf2;
2007 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2009 LPITEMIDLIST pidlCurrent;
2010 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2011 IPersistFolder2_Release(ppf2);
2012 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2014 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE)))
2016 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2019 else if( nOpenAction == ONOPEN_SEARCH )
2021 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2023 COMDLG32_SHFree(pidlCurrent);
2026 ret = FALSE;
2027 break;
2028 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2029 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2031 WCHAR *ext = NULL;
2033 /* update READONLY check box flag */
2034 if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2035 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2036 else
2037 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2039 /* Attach the file extension with file name*/
2040 ext = PathFindExtensionW(lpstrPathAndFile);
2041 if (! *ext)
2043 /* if no extension is specified with file name, then */
2044 /* attach the extension from file filter or default one */
2046 WCHAR *filterExt = NULL;
2047 LPWSTR lpstrFilter = NULL;
2048 static const WCHAR szwDot[] = {'.',0};
2049 int PathLength = strlenW(lpstrPathAndFile);
2051 /* Attach the dot*/
2052 strcatW(lpstrPathAndFile, szwDot);
2054 /*Get the file extension from file type filter*/
2055 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2056 fodInfos->ofnInfos->nFilterIndex-1);
2058 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2059 filterExt = PathFindExtensionW(lpstrFilter);
2061 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2062 strcatW(lpstrPathAndFile, filterExt + 1);
2063 else if ( fodInfos->defext ) /* attach the default file extension*/
2064 strcatW(lpstrPathAndFile, fodInfos->defext);
2066 /* In Open dialog: if file does not exist try without extension */
2067 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2068 lpstrPathAndFile[PathLength] = '\0';
2071 if (fodInfos->defext) /* add default extension */
2073 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2074 if (*ext)
2075 ext++;
2076 if (!lstrcmpiW(fodInfos->defext, ext))
2077 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2078 else
2079 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2082 /* In Save dialog: check if the file already exists */
2083 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2084 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2085 && PathFileExistsW(lpstrPathAndFile))
2087 WCHAR lpstrOverwrite[100];
2088 int answer;
2090 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2091 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2092 MB_YESNO | MB_ICONEXCLAMATION);
2093 if (answer == IDNO)
2095 ret = FALSE;
2096 goto ret;
2100 /* Check that the size of the file does not exceed buffer size.
2101 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2102 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2103 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2105 LPWSTR lpszTemp;
2107 /* fill destination buffer */
2108 if (fodInfos->ofnInfos->lpstrFile)
2110 if(fodInfos->unicode)
2112 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2114 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2115 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2116 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2118 else
2120 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2122 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2123 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2124 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2125 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2129 /* set filename offset */
2130 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2131 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2133 /* set extension offset */
2134 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2135 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2137 /* set the lpstrFileTitle */
2138 if(fodInfos->ofnInfos->lpstrFileTitle)
2140 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2141 if(fodInfos->unicode)
2143 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2144 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2146 else
2148 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2149 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2150 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2154 /* copy currently selected filter to lpstrCustomFilter */
2155 if (fodInfos->ofnInfos->lpstrCustomFilter)
2157 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2158 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2159 NULL, 0, NULL, NULL);
2160 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2162 LPSTR s = ofn->lpstrCustomFilter;
2163 s += strlen(ofn->lpstrCustomFilter)+1;
2164 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2165 s, len, NULL, NULL);
2170 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2171 goto ret;
2173 TRACE("close\n");
2174 FILEDLG95_Clean(hwnd);
2175 ret = EndDialog(hwnd, TRUE);
2177 else
2179 WORD size;
2181 size = strlenW(lpstrPathAndFile) + 1;
2182 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2183 size += 1;
2184 /* return needed size in first two bytes of lpstrFile */
2185 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2186 FILEDLG95_Clean(hwnd);
2187 ret = EndDialog(hwnd, FALSE);
2188 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2190 goto ret;
2192 break;
2195 ret:
2196 if(lpsf) IShellFolder_Release(lpsf);
2197 return ret;
2200 /***********************************************************************
2201 * FILEDLG95_SHELL_Init
2203 * Initialisation of the shell objects
2205 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2207 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2209 TRACE("\n");
2212 * Initialisation of the FileOpenDialogInfos structure
2215 /* Shell */
2217 /*ShellInfos */
2218 fodInfos->ShellInfos.hwndOwner = hwnd;
2220 /* Disable multi-select if flag not set */
2221 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2223 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2225 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2226 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2228 /* Construct the IShellBrowser interface */
2229 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2231 return NOERROR;
2234 /***********************************************************************
2235 * FILEDLG95_SHELL_ExecuteCommand
2237 * Change the folder option and refresh the view
2238 * If the function succeeds, the return value is nonzero.
2240 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2242 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2244 IContextMenu * pcm;
2245 TRACE("(%p,%p)\n", hwnd, lpVerb);
2247 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2248 SVGIO_BACKGROUND,
2249 &IID_IContextMenu,
2250 (LPVOID*)&pcm)))
2252 CMINVOKECOMMANDINFO ci;
2253 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2254 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2255 ci.lpVerb = lpVerb;
2256 ci.hwnd = hwnd;
2258 IContextMenu_InvokeCommand(pcm, &ci);
2259 IContextMenu_Release(pcm);
2262 return FALSE;
2265 /***********************************************************************
2266 * FILEDLG95_SHELL_UpFolder
2268 * Browse to the specified object
2269 * If the function succeeds, the return value is nonzero.
2271 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2273 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2275 TRACE("\n");
2277 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2278 NULL,
2279 SBSP_PARENT)))
2281 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2282 return TRUE;
2284 return FALSE;
2287 /***********************************************************************
2288 * FILEDLG95_SHELL_BrowseToDesktop
2290 * Browse to the Desktop
2291 * If the function succeeds, the return value is nonzero.
2293 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2295 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2296 LPITEMIDLIST pidl;
2297 HRESULT hres;
2299 TRACE("\n");
2301 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2302 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2303 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2304 COMDLG32_SHFree(pidl);
2305 return SUCCEEDED(hres);
2307 /***********************************************************************
2308 * FILEDLG95_SHELL_Clean
2310 * Cleans the memory used by shell objects
2312 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2314 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2316 TRACE("\n");
2318 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2320 /* clean Shell interfaces */
2321 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2322 IShellView_Release(fodInfos->Shell.FOIShellView);
2323 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2324 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2325 if (fodInfos->Shell.FOIDataObject)
2326 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2329 /***********************************************************************
2330 * FILEDLG95_FILETYPE_Init
2332 * Initialisation of the file type combo box
2334 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2336 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2337 int nFilters = 0; /* number of filters */
2338 int nFilterIndexCB;
2340 TRACE("\n");
2342 if(fodInfos->customfilter)
2344 /* customfilter has one entry... title\0ext\0
2345 * Set first entry of combo box item with customfilter
2347 LPWSTR lpstrExt;
2348 LPCWSTR lpstrPos = fodInfos->customfilter;
2350 /* Get the title */
2351 lpstrPos += strlenW(fodInfos->customfilter) + 1;
2353 /* Copy the extensions */
2354 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2355 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2356 strcpyW(lpstrExt,lpstrPos);
2358 /* Add the item at the end of the combo */
2359 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2360 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2361 nFilters++;
2363 if(fodInfos->filter)
2365 LPCWSTR lpstrPos = fodInfos->filter;
2367 for(;;)
2369 /* filter is a list... title\0ext\0......\0\0
2370 * Set the combo item text to the title and the item data
2371 * to the ext
2373 LPCWSTR lpstrDisplay;
2374 LPWSTR lpstrExt;
2376 /* Get the title */
2377 if(! *lpstrPos) break; /* end */
2378 lpstrDisplay = lpstrPos;
2379 lpstrPos += strlenW(lpstrPos) + 1;
2381 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2383 nFilters++;
2385 /* Copy the extensions */
2386 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2387 strcpyW(lpstrExt,lpstrPos);
2388 lpstrPos += strlenW(lpstrPos) + 1;
2390 /* Add the item at the end of the combo */
2391 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2393 /* malformed filters are added anyway... */
2394 if (!*lpstrExt) break;
2399 * Set the current filter to the one specified
2400 * in the initialisation structure
2402 if (fodInfos->filter || fodInfos->customfilter)
2404 LPWSTR lpstrFilter;
2406 /* Check to make sure our index isn't out of bounds. */
2407 if ( fodInfos->ofnInfos->nFilterIndex >
2408 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2409 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2411 /* set default filter index */
2412 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2413 fodInfos->ofnInfos->nFilterIndex = 1;
2415 /* calculate index of Combo Box item */
2416 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2417 if (fodInfos->customfilter == NULL)
2418 nFilterIndexCB--;
2420 /* Set the current index selection. */
2421 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2423 /* Get the corresponding text string from the combo box. */
2424 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2425 nFilterIndexCB);
2427 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2428 lpstrFilter = NULL;
2430 if(lpstrFilter)
2432 DWORD len;
2433 CharLowerW(lpstrFilter); /* lowercase */
2434 len = strlenW(lpstrFilter)+1;
2435 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2436 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2438 } else
2439 fodInfos->ofnInfos->nFilterIndex = 0;
2440 return S_OK;
2443 /***********************************************************************
2444 * FILEDLG95_FILETYPE_OnCommand
2446 * WM_COMMAND of the file type combo box
2447 * If the function succeeds, the return value is nonzero.
2449 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2451 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2453 switch(wNotifyCode)
2455 case CBN_SELENDOK:
2457 LPWSTR lpstrFilter;
2459 /* Get the current item of the filetype combo box */
2460 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2462 /* set the current filter index */
2463 fodInfos->ofnInfos->nFilterIndex = iItem +
2464 (fodInfos->customfilter == NULL ? 1 : 0);
2466 /* Set the current filter with the current selection */
2467 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2469 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2470 iItem);
2471 if((INT_PTR)lpstrFilter != CB_ERR)
2473 DWORD len;
2474 CharLowerW(lpstrFilter); /* lowercase */
2475 len = strlenW(lpstrFilter)+1;
2476 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2477 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2478 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2481 /* Refresh the actual view to display the included items*/
2482 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2485 return FALSE;
2487 /***********************************************************************
2488 * FILEDLG95_FILETYPE_SearchExt
2490 * searches for an extension in the filetype box
2492 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2494 int i, iCount = CBGetCount(hwnd);
2496 TRACE("%s\n", debugstr_w(lpstrExt));
2498 if(iCount != CB_ERR)
2500 for(i=0;i<iCount;i++)
2502 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2503 return i;
2506 return -1;
2509 /***********************************************************************
2510 * FILEDLG95_FILETYPE_Clean
2512 * Clean the memory used by the filetype combo box
2514 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2516 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2517 int iPos;
2518 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2520 TRACE("\n");
2522 /* Delete each string of the combo and their associated data */
2523 if(iCount != CB_ERR)
2525 for(iPos = iCount-1;iPos>=0;iPos--)
2527 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2528 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2531 /* Current filter */
2532 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2536 /***********************************************************************
2537 * FILEDLG95_LOOKIN_Init
2539 * Initialisation of the look in combo box
2542 /* Small helper function, to determine if the unixfs shell extension is rooted
2543 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2545 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2546 HKEY hKey;
2547 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2548 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2549 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2550 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2551 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2552 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2553 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2555 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2556 return FALSE;
2558 RegCloseKey(hKey);
2559 return TRUE;
2562 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2564 IShellFolder *psfRoot, *psfDrives;
2565 IEnumIDList *lpeRoot, *lpeDrives;
2566 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2568 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2570 TRACE("\n");
2572 liInfos->iMaxIndentation = 0;
2574 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2576 /* set item height for both text field and listbox */
2577 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2578 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2580 /* Turn on the extended UI for the combo box like Windows does */
2581 CBSetExtendedUI(hwndCombo, TRUE);
2583 /* Initialise data of Desktop folder */
2584 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2585 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2586 COMDLG32_SHFree(pidlTmp);
2588 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2590 SHGetDesktopFolder(&psfRoot);
2592 if (psfRoot)
2594 /* enumerate the contents of the desktop */
2595 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2597 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2599 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2601 /* If the unixfs extension is rooted, we don't expand the drives by default */
2602 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2604 /* special handling for CSIDL_DRIVES */
2605 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2607 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2609 /* enumerate the drives */
2610 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2612 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2614 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2615 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2616 COMDLG32_SHFree(pidlAbsTmp);
2617 COMDLG32_SHFree(pidlTmp1);
2619 IEnumIDList_Release(lpeDrives);
2621 IShellFolder_Release(psfDrives);
2626 COMDLG32_SHFree(pidlTmp);
2628 IEnumIDList_Release(lpeRoot);
2630 IShellFolder_Release(psfRoot);
2633 COMDLG32_SHFree(pidlDrives);
2636 /***********************************************************************
2637 * FILEDLG95_LOOKIN_DrawItem
2639 * WM_DRAWITEM message handler
2641 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2643 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2644 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2645 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2646 RECT rectText;
2647 RECT rectIcon;
2648 SHFILEINFOA sfi;
2649 HIMAGELIST ilItemImage;
2650 int iIndentation;
2651 TEXTMETRICA tm;
2652 LPSFOLDER tmpFolder;
2655 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2657 TRACE("\n");
2659 if(pDIStruct->itemID == -1)
2660 return 0;
2662 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2663 pDIStruct->itemID)))
2664 return 0;
2667 if(pDIStruct->itemID == liInfos->uSelectedItem)
2669 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2671 &sfi,
2672 sizeof (SHFILEINFOA),
2673 SHGFI_PIDL | SHGFI_SMALLICON |
2674 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2675 SHGFI_DISPLAYNAME );
2677 else
2679 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2681 &sfi,
2682 sizeof (SHFILEINFOA),
2683 SHGFI_PIDL | SHGFI_SMALLICON |
2684 SHGFI_SYSICONINDEX |
2685 SHGFI_DISPLAYNAME);
2688 /* Is this item selected ? */
2689 if(pDIStruct->itemState & ODS_SELECTED)
2691 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2692 SetBkColor(pDIStruct->hDC,crHighLight);
2693 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2695 else
2697 SetTextColor(pDIStruct->hDC,crText);
2698 SetBkColor(pDIStruct->hDC,crWin);
2699 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2702 /* Do not indent item if drawing in the edit of the combo */
2703 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2705 iIndentation = 0;
2706 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2708 &sfi,
2709 sizeof (SHFILEINFOA),
2710 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2711 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2714 else
2716 iIndentation = tmpFolder->m_iIndent;
2718 /* Draw text and icon */
2720 /* Initialise the icon display area */
2721 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2722 rectIcon.top = pDIStruct->rcItem.top;
2723 rectIcon.right = rectIcon.left + ICONWIDTH;
2724 rectIcon.bottom = pDIStruct->rcItem.bottom;
2726 /* Initialise the text display area */
2727 GetTextMetricsA(pDIStruct->hDC, &tm);
2728 rectText.left = rectIcon.right;
2729 rectText.top =
2730 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2731 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2732 rectText.bottom =
2733 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2735 /* Draw the icon from the image list */
2736 ImageList_Draw(ilItemImage,
2737 sfi.iIcon,
2738 pDIStruct->hDC,
2739 rectIcon.left,
2740 rectIcon.top,
2741 ILD_TRANSPARENT );
2743 /* Draw the associated text */
2744 if(sfi.szDisplayName)
2745 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2748 return NOERROR;
2751 /***********************************************************************
2752 * FILEDLG95_LOOKIN_OnCommand
2754 * LookIn combo box WM_COMMAND message handler
2755 * If the function succeeds, the return value is nonzero.
2757 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2759 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2761 TRACE("%p\n", fodInfos);
2763 switch(wNotifyCode)
2765 case CBN_SELENDOK:
2767 LPSFOLDER tmpFolder;
2768 int iItem;
2770 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2772 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2773 iItem)))
2774 return FALSE;
2777 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2778 tmpFolder->pidlItem,
2779 SBSP_ABSOLUTE)))
2781 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2782 return TRUE;
2784 break;
2788 return FALSE;
2791 /***********************************************************************
2792 * FILEDLG95_LOOKIN_AddItem
2794 * Adds an absolute pidl item to the lookin combo box
2795 * returns the index of the inserted item
2797 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2799 LPITEMIDLIST pidlNext;
2800 SHFILEINFOA sfi;
2801 SFOLDER *tmpFolder;
2802 LookInInfos *liInfos;
2804 TRACE("%08x\n", iInsertId);
2806 if(!pidl)
2807 return -1;
2809 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2810 return -1;
2812 tmpFolder = MemAlloc(sizeof(SFOLDER));
2813 tmpFolder->m_iIndent = 0;
2815 /* Calculate the indentation of the item in the lookin*/
2816 pidlNext = pidl;
2817 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2819 tmpFolder->m_iIndent++;
2822 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2824 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2825 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2827 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2828 SHGetFileInfoA((LPSTR)pidl,
2830 &sfi,
2831 sizeof(sfi),
2832 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2833 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2835 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2837 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2839 int iItemID;
2841 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2843 /* Add the item at the end of the list */
2844 if(iInsertId < 0)
2846 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2848 /* Insert the item at the iInsertId position*/
2849 else
2851 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2854 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2855 return iItemID;
2858 COMDLG32_SHFree( tmpFolder->pidlItem );
2859 MemFree( tmpFolder );
2860 return -1;
2864 /***********************************************************************
2865 * FILEDLG95_LOOKIN_InsertItemAfterParent
2867 * Insert an item below its parent
2869 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2872 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2873 int iParentPos;
2875 TRACE("\n");
2877 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2879 if(iParentPos < 0)
2881 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2884 /* Free pidlParent memory */
2885 COMDLG32_SHFree((LPVOID)pidlParent);
2887 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2890 /***********************************************************************
2891 * FILEDLG95_LOOKIN_SelectItem
2893 * Adds an absolute pidl item to the lookin combo box
2894 * returns the index of the inserted item
2896 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2898 int iItemPos;
2899 LookInInfos *liInfos;
2901 TRACE("\n");
2903 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2905 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2907 if(iItemPos < 0)
2909 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2910 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2913 else
2915 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2916 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2918 int iRemovedItem;
2920 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2921 break;
2922 if(iRemovedItem < iItemPos)
2923 iItemPos--;
2927 CBSetCurSel(hwnd,iItemPos);
2928 liInfos->uSelectedItem = iItemPos;
2930 return 0;
2934 /***********************************************************************
2935 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2937 * Remove the item with an expansion level over iExpansionLevel
2939 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2941 int iItemPos;
2943 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2945 TRACE("\n");
2947 if(liInfos->iMaxIndentation <= 2)
2948 return -1;
2950 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2952 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2953 COMDLG32_SHFree(tmpFolder->pidlItem);
2954 MemFree(tmpFolder);
2955 CBDeleteString(hwnd,iItemPos);
2956 liInfos->iMaxIndentation--;
2958 return iItemPos;
2961 return -1;
2964 /***********************************************************************
2965 * FILEDLG95_LOOKIN_SearchItem
2967 * Search for pidl in the lookin combo box
2968 * returns the index of the found item
2970 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2972 int i = 0;
2973 int iCount = CBGetCount(hwnd);
2975 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2977 if (iCount != CB_ERR)
2979 for(;i<iCount;i++)
2981 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2983 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2984 return i;
2985 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2986 return i;
2990 return -1;
2993 /***********************************************************************
2994 * FILEDLG95_LOOKIN_Clean
2996 * Clean the memory used by the lookin combo box
2998 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3000 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3001 int iPos;
3002 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3004 TRACE("\n");
3006 /* Delete each string of the combo and their associated data */
3007 if (iCount != CB_ERR)
3009 for(iPos = iCount-1;iPos>=0;iPos--)
3011 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3012 COMDLG32_SHFree(tmpFolder->pidlItem);
3013 MemFree(tmpFolder);
3014 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3018 /* LookInInfos structure */
3019 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3022 /***********************************************************************
3023 * FILEDLG95_FILENAME_FillFromSelection
3025 * fills the edit box from the cached DataObject
3027 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3029 FileOpenDlgInfos *fodInfos;
3030 LPITEMIDLIST pidl;
3031 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3032 char lpstrTemp[MAX_PATH];
3033 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
3035 TRACE("\n");
3036 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3038 /* Count how many files we have */
3039 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3041 /* calculate the string length, count files */
3042 if (nFileSelected >= 1)
3044 nLength += 3; /* first and last quotes, trailing \0 */
3045 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3047 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3049 if (pidl)
3051 /* get the total length of the selected file names */
3052 lpstrTemp[0] = '\0';
3053 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3055 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3057 nLength += strlen( lpstrTemp ) + 3;
3058 nFiles++;
3060 COMDLG32_SHFree( pidl );
3065 /* allocate the buffer */
3066 if (nFiles <= 1) nLength = MAX_PATH;
3067 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
3068 lpstrAllFile[0] = '\0';
3070 /* Generate the string for the edit control */
3071 if(nFiles >= 1)
3073 lpstrCurrFile = lpstrAllFile;
3074 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3076 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3078 if (pidl)
3080 /* get the file name */
3081 lpstrTemp[0] = '\0';
3082 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3084 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3086 if ( nFiles > 1)
3088 *lpstrCurrFile++ = '\"';
3089 strcpy( lpstrCurrFile, lpstrTemp );
3090 lpstrCurrFile += strlen( lpstrTemp );
3091 strcpy( lpstrCurrFile, "\" " );
3092 lpstrCurrFile += 2;
3094 else
3096 strcpy( lpstrAllFile, lpstrTemp );
3099 COMDLG32_SHFree( (LPVOID) pidl );
3102 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3104 /* Select the file name like Windows does */
3105 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
3107 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3111 /* copied from shell32 to avoid linking to it
3112 * FIXME: why? shell32 is already linked
3114 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3116 switch (src->uType)
3118 case STRRET_WSTR:
3119 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
3120 COMDLG32_SHFree(src->u.pOleStr);
3121 break;
3123 case STRRET_CSTR:
3124 lstrcpynA((LPSTR)dest, src->u.cStr, len);
3125 break;
3127 case STRRET_OFFSET:
3128 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
3129 break;
3131 default:
3132 FIXME("unknown type!\n");
3133 if (len)
3135 *(LPSTR)dest = '\0';
3137 return(E_FAIL);
3139 return S_OK;
3142 /***********************************************************************
3143 * FILEDLG95_FILENAME_GetFileNames
3145 * Copies the filenames to a delimited string list.
3146 * The delimiter is specified by the parameter 'separator',
3147 * usually either a space or a nul
3149 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3151 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3152 UINT nStrCharCount = 0; /* index in src buffer */
3153 UINT nFileIndex = 0; /* index in dest buffer */
3154 UINT nFileCount = 0; /* number of files */
3155 UINT nStrLen = 0; /* length of string in edit control */
3156 LPWSTR lpstrEdit; /* buffer for string from edit control */
3158 TRACE("\n");
3160 /* get the filenames from the edit control */
3161 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3162 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3163 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3165 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3167 /* we might get single filename without any '"',
3168 * so we need nStrLen + terminating \0 + end-of-list \0 */
3169 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3170 *sizeUsed = 0;
3172 /* build delimited file list from filenames */
3173 while ( nStrCharCount <= nStrLen )
3175 if ( lpstrEdit[nStrCharCount]=='"' )
3177 nStrCharCount++;
3178 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3180 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3181 (*sizeUsed)++;
3182 nStrCharCount++;
3184 (*lpstrFileList)[nFileIndex++] = separator;
3185 (*sizeUsed)++;
3186 nFileCount++;
3188 nStrCharCount++;
3191 /* single, unquoted string */
3192 if ((nStrLen > 0) && (*sizeUsed == 0) )
3194 strcpyW(*lpstrFileList, lpstrEdit);
3195 nFileIndex = strlenW(lpstrEdit) + 1;
3196 (*sizeUsed) = nFileIndex;
3197 nFileCount = 1;
3200 /* trailing \0 */
3201 (*lpstrFileList)[nFileIndex] = '\0';
3202 (*sizeUsed)++;
3204 MemFree(lpstrEdit);
3205 return nFileCount;
3208 #define SETDefFormatEtc(fe,cf,med) \
3210 (fe).cfFormat = cf;\
3211 (fe).dwAspect = DVASPECT_CONTENT; \
3212 (fe).ptd =NULL;\
3213 (fe).tymed = med;\
3214 (fe).lindex = -1;\
3218 * DATAOBJECT Helper functions
3221 /***********************************************************************
3222 * COMCTL32_ReleaseStgMedium
3224 * like ReleaseStgMedium from ole32
3226 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3228 if(medium.pUnkForRelease)
3230 IUnknown_Release(medium.pUnkForRelease);
3232 else
3234 GlobalUnlock(medium.u.hGlobal);
3235 GlobalFree(medium.u.hGlobal);
3239 /***********************************************************************
3240 * GetPidlFromDataObject
3242 * Return pidl(s) by number from the cached DataObject
3244 * nPidlIndex=0 gets the fully qualified root path
3246 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3249 STGMEDIUM medium;
3250 FORMATETC formatetc;
3251 LPITEMIDLIST pidl = NULL;
3253 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3255 if (!doSelected)
3256 return NULL;
3258 /* Set the FORMATETC structure*/
3259 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3261 /* Get the pidls from IDataObject */
3262 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3264 LPIDA cida = GlobalLock(medium.u.hGlobal);
3265 if(nPidlIndex <= cida->cidl)
3267 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3269 COMCTL32_ReleaseStgMedium(medium);
3271 return pidl;
3274 /***********************************************************************
3275 * GetNumSelected
3277 * Return the number of selected items in the DataObject.
3280 UINT GetNumSelected( IDataObject *doSelected )
3282 UINT retVal = 0;
3283 STGMEDIUM medium;
3284 FORMATETC formatetc;
3286 TRACE("sv=%p\n", doSelected);
3288 if (!doSelected) return 0;
3290 /* Set the FORMATETC structure*/
3291 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3293 /* Get the pidls from IDataObject */
3294 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3296 LPIDA cida = GlobalLock(medium.u.hGlobal);
3297 retVal = cida->cidl;
3298 COMCTL32_ReleaseStgMedium(medium);
3299 return retVal;
3301 return 0;
3305 * TOOLS
3308 /***********************************************************************
3309 * GetName
3311 * Get the pidl's display name (relative to folder) and
3312 * put it in lpstrFileName.
3314 * Return NOERROR on success,
3315 * E_FAIL otherwise
3318 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3320 STRRET str;
3321 HRESULT hRes;
3323 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3325 if(!lpsf)
3327 SHGetDesktopFolder(&lpsf);
3328 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3329 IShellFolder_Release(lpsf);
3330 return hRes;
3333 /* Get the display name of the pidl relative to the folder */
3334 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3336 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3338 return E_FAIL;
3341 /***********************************************************************
3342 * GetShellFolderFromPidl
3344 * pidlRel is the item pidl relative
3345 * Return the IShellFolder of the absolute pidl
3347 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3349 IShellFolder *psf = NULL,*psfParent;
3351 TRACE("%p\n", pidlAbs);
3353 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3355 psf = psfParent;
3356 if(pidlAbs && pidlAbs->mkid.cb)
3358 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3360 IShellFolder_Release(psfParent);
3361 return psf;
3364 /* return the desktop */
3365 return psfParent;
3367 return NULL;
3370 /***********************************************************************
3371 * GetParentPidl
3373 * Return the LPITEMIDLIST to the parent of the pidl in the list
3375 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3377 LPITEMIDLIST pidlParent;
3379 TRACE("%p\n", pidl);
3381 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3382 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3384 return pidlParent;
3387 /***********************************************************************
3388 * GetPidlFromName
3390 * returns the pidl of the file name relative to folder
3391 * NULL if an error occurred
3393 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3395 LPITEMIDLIST pidl = NULL;
3396 ULONG ulEaten;
3398 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3400 if(!lpcstrFileName) return NULL;
3401 if(!*lpcstrFileName) return NULL;
3403 if(!lpsf)
3405 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3406 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3407 IShellFolder_Release(lpsf);
3410 else
3412 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3414 return pidl;
3419 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3421 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3422 HRESULT ret;
3424 TRACE("%p, %p\n", psf, pidl);
3426 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3428 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3429 /* see documentation shell 4.1*/
3430 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3433 /***********************************************************************
3434 * BrowseSelectedFolder
3436 static BOOL BrowseSelectedFolder(HWND hwnd)
3438 BOOL bBrowseSelFolder = FALSE;
3439 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3441 TRACE("\n");
3443 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3445 LPITEMIDLIST pidlSelection;
3447 /* get the file selected */
3448 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3449 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3451 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3452 pidlSelection, SBSP_RELATIVE ) ) )
3454 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3455 ' ','n','o','t',' ','e','x','i','s','t',0};
3456 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3458 bBrowseSelFolder = TRUE;
3459 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3461 COMDLG32_SHFree( pidlSelection );
3464 return bBrowseSelFolder;
3468 * Memory allocation methods */
3469 static void *MemAlloc(UINT size)
3471 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3474 static void MemFree(void *mem)
3476 HeapFree(GetProcessHeap(),0,mem);
3480 * Old-style (win3.1) dialogs */
3482 /***********************************************************************
3483 * FD32_GetTemplate [internal]
3485 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3486 * by a 32 bits application
3489 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3491 LPOPENFILENAMEW ofnW = lfs->ofnW;
3492 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3493 HANDLE hDlgTmpl;
3495 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3497 if (!(lfs->template = LockResource( ofnW->hInstance )))
3499 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3500 return FALSE;
3503 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3505 HRSRC hResInfo;
3506 if (priv->ofnA)
3507 hResInfo = FindResourceA(priv->ofnA->hInstance,
3508 priv->ofnA->lpTemplateName,
3509 (LPSTR)RT_DIALOG);
3510 else
3511 hResInfo = FindResourceW(ofnW->hInstance,
3512 ofnW->lpTemplateName,
3513 (LPWSTR)RT_DIALOG);
3514 if (!hResInfo)
3516 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3517 return FALSE;
3519 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3520 hResInfo)) ||
3521 !(lfs->template = LockResource(hDlgTmpl)))
3523 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3524 return FALSE;
3526 } else { /* get it from internal Wine resource */
3527 HRSRC hResInfo;
3528 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3529 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3531 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3532 return FALSE;
3534 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3535 !(lfs->template = LockResource( hDlgTmpl )))
3537 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3538 return FALSE;
3541 return TRUE;
3545 /************************************************************************
3546 * FD32_Init [internal]
3547 * called from the common 16/32 code to initialize 32 bit data
3549 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3551 BOOL IsUnicode = (BOOL) data;
3552 PFD32_PRIVATE priv;
3554 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3555 lfs->private1632 = priv;
3556 if (NULL == lfs->private1632) return FALSE;
3557 if (IsUnicode)
3559 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3560 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3561 if (lfs->ofnW->lpfnHook)
3562 lfs->hook = TRUE;
3564 else
3566 priv->ofnA = (LPOPENFILENAMEA) lParam;
3567 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3568 if (priv->ofnA->lpfnHook)
3569 lfs->hook = TRUE;
3570 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3571 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3574 if (! FD32_GetTemplate(lfs)) return FALSE;
3576 return TRUE;
3579 /***********************************************************************
3580 * FD32_CallWindowProc [internal]
3582 * called from the common 16/32 code to call the appropriate hook
3584 static BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
3585 LPARAM lParam)
3587 BOOL ret;
3588 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3590 if (priv->ofnA)
3592 TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3593 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3594 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3595 TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3596 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3597 return ret;
3600 TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3601 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3602 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3603 TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3604 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3605 return ret;
3608 /***********************************************************************
3609 * FD32_UpdateResult [internal]
3610 * update the real client structures if any
3612 static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs)
3614 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3615 LPOPENFILENAMEW ofnW = lfs->ofnW;
3617 if (priv->ofnA)
3619 if (ofnW->nMaxFile &&
3620 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3621 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3622 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3623 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3624 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3628 /***********************************************************************
3629 * FD32_UpdateFileTitle [internal]
3630 * update the real client structures if any
3632 static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs)
3634 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3635 LPOPENFILENAMEW ofnW = lfs->ofnW;
3637 if (priv->ofnA)
3639 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3640 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3641 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3646 /***********************************************************************
3647 * FD32_SendLbGetCurSel [internal]
3648 * retrieve selected listbox item
3650 static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs)
3652 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3656 /************************************************************************
3657 * FD32_Destroy [internal]
3658 * called from the common 16/32 code to cleanup 32 bit data
3660 static void CALLBACK FD32_Destroy(PFD31_DATA lfs)
3662 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3664 /* if ofnW has been allocated, have to free everything in it */
3665 if (NULL != priv && NULL != priv->ofnA)
3667 FD31_FreeOfnW(lfs->ofnW);
3668 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3672 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3674 callbacks->Init = FD32_Init;
3675 callbacks->CWP = FD32_CallWindowProc;
3676 callbacks->UpdateResult = FD32_UpdateResult;
3677 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3678 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3679 callbacks->Destroy = FD32_Destroy;
3682 /***********************************************************************
3683 * FD32_WMMeasureItem [internal]
3685 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3687 LPMEASUREITEMSTRUCT lpmeasure;
3689 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3690 lpmeasure->itemHeight = FD31_GetFldrHeight();
3691 return TRUE;
3695 /***********************************************************************
3696 * FileOpenDlgProc [internal]
3697 * Used for open and save, in fact.
3699 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3700 WPARAM wParam, LPARAM lParam)
3702 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3704 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
3705 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3707 INT_PTR lRet;
3708 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3709 if (lRet)
3710 return lRet; /* else continue message processing */
3712 switch (wMsg)
3714 case WM_INITDIALOG:
3715 return FD31_WMInitDialog(hWnd, wParam, lParam);
3717 case WM_MEASUREITEM:
3718 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3720 case WM_DRAWITEM:
3721 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3723 case WM_COMMAND:
3724 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3725 #if 0
3726 case WM_CTLCOLOR:
3727 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3728 switch (HIWORD(lParam))
3730 case CTLCOLOR_BTN:
3731 SetTextColor((HDC16)wParam, 0x00000000);
3732 return hGRAYBrush;
3733 case CTLCOLOR_STATIC:
3734 SetTextColor((HDC16)wParam, 0x00000000);
3735 return hGRAYBrush;
3737 break;
3738 #endif
3740 return FALSE;
3744 /***********************************************************************
3745 * GetFileName31A [internal]
3747 * Creates a win31 style dialog box for the user to select a file to open/save.
3749 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3750 UINT dlgType /* type dialogue : open/save */
3753 HINSTANCE hInst;
3754 BOOL bRet = FALSE;
3755 PFD31_DATA lfs;
3756 FD31_CALLBACKS callbacks;
3758 if (!lpofn || !FD31_Init()) return FALSE;
3760 TRACE("ofn flags %08lx\n", lpofn->Flags);
3761 FD32_SetupCallbacks(&callbacks);
3762 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3763 if (lfs)
3765 hInst = (HINSTANCE)GetWindowLongPtrA( lpofn->hwndOwner, GWLP_HINSTANCE );
3766 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3767 FD32_FileOpenDlgProc, (LPARAM)lfs);
3768 FD31_DestroyPrivate(lfs);
3771 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3772 return bRet;
3775 /***********************************************************************
3776 * GetFileName31W [internal]
3778 * Creates a win31 style dialog box for the user to select a file to open/save
3780 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3781 UINT dlgType /* type dialogue : open/save */
3784 HINSTANCE hInst;
3785 BOOL bRet = FALSE;
3786 PFD31_DATA lfs;
3787 FD31_CALLBACKS callbacks;
3789 if (!lpofn || !FD31_Init()) return FALSE;
3791 FD32_SetupCallbacks(&callbacks);
3792 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3793 if (lfs)
3795 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3796 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3797 FD32_FileOpenDlgProc, (LPARAM)lfs);
3798 FD31_DestroyPrivate(lfs);
3801 TRACE("file %s, file offset %d, ext offset %d\n",
3802 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3803 return bRet;
3806 /* ------------------ APIs ---------------------- */
3808 /***********************************************************************
3809 * GetOpenFileNameA (COMDLG32.@)
3811 * Creates a dialog box for the user to select a file to open.
3813 * RETURNS
3814 * TRUE on success: user enters a valid file
3815 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3818 BOOL WINAPI GetOpenFileNameA(
3819 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3821 BOOL win16look = FALSE;
3823 TRACE("flags %08lx\n", ofn->Flags);
3825 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3826 if (ofn->Flags & OFN_FILEMUSTEXIST)
3827 ofn->Flags |= OFN_PATHMUSTEXIST;
3829 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3830 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3832 if (win16look)
3833 return GetFileName31A(ofn, OPEN_DIALOG);
3834 else
3835 return GetFileDialog95A(ofn, OPEN_DIALOG);
3838 /***********************************************************************
3839 * GetOpenFileNameW (COMDLG32.@)
3841 * Creates a dialog box for the user to select a file to open.
3843 * RETURNS
3844 * TRUE on success: user enters a valid file
3845 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3848 BOOL WINAPI GetOpenFileNameW(
3849 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3851 BOOL win16look = FALSE;
3853 TRACE("flags %08lx\n", ofn->Flags);
3855 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3856 if (ofn->Flags & OFN_FILEMUSTEXIST)
3857 ofn->Flags |= OFN_PATHMUSTEXIST;
3859 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3860 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3862 if (win16look)
3863 return GetFileName31W(ofn, OPEN_DIALOG);
3864 else
3865 return GetFileDialog95W(ofn, OPEN_DIALOG);
3869 /***********************************************************************
3870 * GetSaveFileNameA (COMDLG32.@)
3872 * Creates a dialog box for the user to select a file to save.
3874 * RETURNS
3875 * TRUE on success: user enters a valid file
3876 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3879 BOOL WINAPI GetSaveFileNameA(
3880 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3882 BOOL win16look = FALSE;
3884 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3885 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3887 if (win16look)
3888 return GetFileName31A(ofn, SAVE_DIALOG);
3889 else
3890 return GetFileDialog95A(ofn, SAVE_DIALOG);
3893 /***********************************************************************
3894 * GetSaveFileNameW (COMDLG32.@)
3896 * Creates a dialog box for the user to select a file to save.
3898 * RETURNS
3899 * TRUE on success: user enters a valid file
3900 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3903 BOOL WINAPI GetSaveFileNameW(
3904 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3906 BOOL win16look = FALSE;
3908 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3909 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3911 if (win16look)
3912 return GetFileName31W(ofn, SAVE_DIALOG);
3913 else
3914 return GetFileDialog95W(ofn, SAVE_DIALOG);