Changes of picasa-wine-2.2.2820-5 except to configure
[wine/hacks.git] / dlls / commdlg / filedlg.c
blobcab34b831fa95d22aa795185cbb50cffe103c5e9
1 /*
2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_CREATEPROMPT, OFN_DONTADDTORECENT,
40 * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING,
41 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
42 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
44 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
49 #include "config.h"
50 #include "wine/port.h"
52 #include <ctype.h>
53 #include <stdlib.h>
54 #include <stdarg.h>
55 #include <stdio.h>
56 #include <string.h>
58 #define COBJMACROS
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
62 #include "windef.h"
63 #include "winbase.h"
64 #include "winreg.h"
65 #include "winternl.h"
66 #include "winnls.h"
67 #include "wine/unicode.h"
68 #include "wingdi.h"
69 #include "winuser.h"
70 #include "winreg.h"
71 #include "commdlg.h"
72 #include "dlgs.h"
73 #include "cdlg.h"
74 #include "filedlg31.h"
75 #include "wine/debug.h"
76 #include "cderr.h"
77 #include "shellapi.h"
78 #include "shlguid.h"
79 #include "shlobj.h"
80 #include "filedlgbrowser.h"
81 #include "shlwapi.h"
83 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
85 #define UNIMPLEMENTED_FLAGS \
86 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
87 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
88 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
89 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
91 #define IsHooked(fodInfos) \
92 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
93 /***********************************************************************
94 * Data structure and global variables
96 typedef struct SFolder
98 int m_iImageIndex; /* Index of picture in image list */
99 HIMAGELIST hImgList;
100 int m_iIndent; /* Indentation index */
101 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
103 } SFOLDER,*LPSFOLDER;
105 typedef struct tagLookInInfo
107 int iMaxIndentation;
108 UINT uSelectedItem;
109 } LookInInfos;
111 typedef struct tagFD32_PRIVATE
113 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
114 } FD32_PRIVATE, *PFD32_PRIVATE;
117 /***********************************************************************
118 * Defines and global variables
121 /* Draw item constant */
122 #define ICONWIDTH 18
123 #define XTEXTOFFSET 3
125 /* AddItem flags*/
126 #define LISTEND -1
128 /* SearchItem methods */
129 #define SEARCH_PIDL 1
130 #define SEARCH_EXP 2
131 #define ITEM_NOTFOUND -1
133 /* Undefined windows message sent by CreateViewObject*/
134 #define WM_GETISHELLBROWSER WM_USER+7
136 /* NOTE
137 * Those macros exist in windowsx.h. However, you can't really use them since
138 * they rely on the UNICODE defines and can't be used inside Wine itself.
141 /* Combo box macros */
142 #define CBAddString(hwnd,str) \
143 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
144 #define CBAddStringW(hwnd,str) \
145 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
147 #define CBInsertString(hwnd,str,pos) \
148 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
150 #define CBDeleteString(hwnd,pos) \
151 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
153 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
154 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
156 #define CBGetItemDataPtr(hwnd,iItemId) \
157 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
159 #define CBGetLBText(hwnd,iItemId,str) \
160 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
162 #define CBGetCurSel(hwnd) \
163 SendMessageA(hwnd,CB_GETCURSEL,0,0);
165 #define CBSetCurSel(hwnd,pos) \
166 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
168 #define CBGetCount(hwnd) \
169 SendMessageA(hwnd,CB_GETCOUNT,0,0);
170 #define CBShowDropDown(hwnd,show) \
171 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
172 #define CBSetItemHeight(hwnd,index,height) \
173 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
175 #define CBSetExtendedUI(hwnd,flag) \
176 SendMessageA(hwnd,CB_SETEXTENDEDUI,(WPARAM)(flag),0)
178 const char *FileOpenDlgInfosStr = "FileOpenDlgInfos"; /* windows property description string */
179 const char *LookInInfosStr = "LookInInfos"; /* LOOKIN combo box property */
181 /***********************************************************************
182 * Prototypes
185 /* Internal functions used by the dialog */
186 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
187 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
188 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
189 BOOL FILEDLG95_OnOpen(HWND hwnd);
190 static LRESULT FILEDLG95_InitControls(HWND hwnd);
191 static void FILEDLG95_Clean(HWND hwnd);
193 /* Functions used by the shell navigation */
194 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
195 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
196 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
197 static void FILEDLG95_SHELL_Clean(HWND hwnd);
198 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
200 /* Functions used by the EDIT box */
201 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator);
203 /* Functions used by the filetype combo box */
204 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
205 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
206 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
207 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
209 /* Functions used by the Look In combo box */
210 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
211 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
212 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
213 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
214 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
215 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
216 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
217 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
218 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
220 /* Miscellaneous tool functions */
221 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
222 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
223 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
224 LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
226 /* Shell memory allocation */
227 static void *MemAlloc(UINT size);
228 static void MemFree(void *mem);
230 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
231 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode);
232 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
233 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
234 static BOOL BrowseSelectedFolder(HWND hwnd);
236 /***********************************************************************
237 * GetFileName95
239 * Creates an Open common dialog box that lets the user select
240 * the drive, directory, and the name of a file or set of files to open.
242 * IN : The FileOpenDlgInfos structure associated with the dialog
243 * OUT : TRUE on success
244 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
246 static BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
249 LRESULT lRes;
250 LPCVOID template;
251 HRSRC hRes;
252 HANDLE hDlgTmpl = 0;
253 HRESULT hr;
255 /* test for missing functionality */
256 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
258 FIXME("Flags 0x%08lx not yet implemented\n",
259 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
262 /* Create the dialog from a template */
264 if(!(hRes = FindResourceA(COMDLG32_hInstance,MAKEINTRESOURCEA(NEWFILEOPENORD),(LPSTR)RT_DIALOG)))
266 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
267 return FALSE;
269 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
270 !(template = LockResource( hDlgTmpl )))
272 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
273 return FALSE;
276 /* old style hook messages */
277 if (IsHooked(fodInfos))
279 fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
280 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
281 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
282 fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
285 /* Some shell namespace extensions depend on COM being initialized. */
286 hr = OleInitialize(NULL);
288 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
289 (LPDLGTEMPLATEA) template,
290 fodInfos->ofnInfos->hwndOwner,
291 FileOpenDlgProc95,
292 (LPARAM) fodInfos);
293 if (SUCCEEDED(hr))
294 OleUninitialize();
296 /* Unable to create the dialog */
297 if( lRes == -1)
298 return FALSE;
300 return lRes;
303 /***********************************************************************
304 * GetFileDialog95A
306 * Call GetFileName95 with this structure and clean the memory.
308 * IN : The OPENFILENAMEA initialisation structure passed to
309 * GetOpenFileNameA win api function (see filedlg.c)
311 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
313 BOOL ret;
314 FileOpenDlgInfos fodInfos;
315 LPSTR lpstrSavDir = NULL;
316 LPWSTR title = NULL;
317 LPWSTR defext = NULL;
318 LPWSTR filter = NULL;
319 LPWSTR customfilter = NULL;
321 /* Initialize FileOpenDlgInfos structure */
322 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
324 /* Pass in the original ofn */
325 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
327 /* save current directory */
328 if (ofn->Flags & OFN_NOCHANGEDIR)
330 lpstrSavDir = MemAlloc(MAX_PATH);
331 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
334 fodInfos.unicode = FALSE;
336 /* convert all the input strings to unicode */
337 if(ofn->lpstrInitialDir)
339 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
340 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
341 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
343 else
344 fodInfos.initdir = NULL;
346 if(ofn->lpstrFile)
348 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
349 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
351 else
352 fodInfos.filename = NULL;
354 if(ofn->lpstrDefExt)
356 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
357 defext = MemAlloc((len+1)*sizeof(WCHAR));
358 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
360 fodInfos.defext = defext;
362 if(ofn->lpstrTitle)
364 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
365 title = MemAlloc((len+1)*sizeof(WCHAR));
366 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
368 fodInfos.title = title;
370 if (ofn->lpstrFilter)
372 LPCSTR s;
373 int n, len;
375 /* filter is a list... title\0ext\0......\0\0 */
376 s = ofn->lpstrFilter;
377 while (*s) s = s+strlen(s)+1;
378 s++;
379 n = s - ofn->lpstrFilter;
380 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
381 filter = MemAlloc(len*sizeof(WCHAR));
382 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
384 fodInfos.filter = filter;
386 /* convert lpstrCustomFilter */
387 if (ofn->lpstrCustomFilter)
389 LPCSTR s;
390 int n, len;
392 /* customfilter contains a pair of strings... title\0ext\0 */
393 s = ofn->lpstrCustomFilter;
394 if (*s) s = s+strlen(s)+1;
395 if (*s) s = s+strlen(s)+1;
396 n = s - ofn->lpstrCustomFilter;
397 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
398 customfilter = MemAlloc(len*sizeof(WCHAR));
399 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
401 fodInfos.customfilter = customfilter;
403 /* Initialize the dialog property */
404 fodInfos.DlgInfos.dwDlgProp = 0;
405 fodInfos.DlgInfos.hwndCustomDlg = NULL;
407 switch(iDlgType)
409 case OPEN_DIALOG :
410 ret = GetFileName95(&fodInfos);
411 break;
412 case SAVE_DIALOG :
413 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
414 ret = GetFileName95(&fodInfos);
415 break;
416 default :
417 ret = 0;
420 if (lpstrSavDir)
422 SetCurrentDirectoryA(lpstrSavDir);
423 MemFree(lpstrSavDir);
426 if(title)
427 MemFree(title);
428 if(defext)
429 MemFree(defext);
430 if(filter)
431 MemFree(filter);
432 if(customfilter)
433 MemFree(customfilter);
434 if(fodInfos.initdir)
435 MemFree(fodInfos.initdir);
437 if(fodInfos.filename)
438 MemFree(fodInfos.filename);
440 TRACE("selected file: %s\n",ofn->lpstrFile);
442 return ret;
445 /***********************************************************************
446 * GetFileDialog95W
448 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
449 * Call GetFileName95 with this structure and clean the memory.
452 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
454 BOOL ret;
455 FileOpenDlgInfos fodInfos;
456 LPWSTR lpstrSavDir = NULL;
458 /* Initialize FileOpenDlgInfos structure */
459 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
461 /* Pass in the original ofn */
462 fodInfos.ofnInfos = ofn;
464 fodInfos.title = ofn->lpstrTitle;
465 fodInfos.defext = ofn->lpstrDefExt;
466 fodInfos.filter = ofn->lpstrFilter;
467 fodInfos.customfilter = ofn->lpstrCustomFilter;
469 /* convert string arguments, save others */
470 if(ofn->lpstrFile)
472 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
473 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
475 else
476 fodInfos.filename = NULL;
478 if(ofn->lpstrInitialDir)
480 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
481 DWORD len = strlenW(ofn->lpstrInitialDir)+1;
482 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
483 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
485 else
486 fodInfos.initdir = NULL;
488 /* save current directory */
489 if (ofn->Flags & OFN_NOCHANGEDIR)
491 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
492 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
495 fodInfos.unicode = TRUE;
497 switch(iDlgType)
499 case OPEN_DIALOG :
500 ret = GetFileName95(&fodInfos);
501 break;
502 case SAVE_DIALOG :
503 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
504 ret = GetFileName95(&fodInfos);
505 break;
506 default :
507 ret = 0;
510 if (lpstrSavDir)
512 SetCurrentDirectoryW(lpstrSavDir);
513 MemFree(lpstrSavDir);
516 /* restore saved IN arguments and convert OUT arguments back */
517 MemFree(fodInfos.filename);
518 MemFree(fodInfos.initdir);
519 return ret;
522 /******************************************************************************
523 * COMDLG32_GetDisplayNameOf [internal]
525 * Helper function to get the display name for a pidl.
527 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
528 LPSHELLFOLDER psfDesktop;
529 STRRET strret;
531 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
532 return FALSE;
534 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
535 IShellFolder_Release(psfDesktop);
536 return FALSE;
539 IShellFolder_Release(psfDesktop);
540 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
543 /***********************************************************************
544 * ArrangeCtrlPositions [internal]
546 * NOTE: Do not change anything here without a lot of testing.
548 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
550 HWND hwndChild, hwndStc32;
551 RECT rectParent, rectChild, rectStc32;
552 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
554 /* Take into account if open as read only checkbox and help button
555 * are hidden
557 if (hide_help)
559 RECT rectHelp, rectCancel;
560 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
561 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
562 /* subtract the height of the help button plus the space between
563 * the help button and the cancel button to the height of the dialog
565 help_fixup = rectHelp.bottom - rectCancel.bottom;
569 There are two possibilities to add components to the default file dialog box.
571 By default, all the new components are added below the standard dialog box (the else case).
573 However, if there is a static text component with the stc32 id, a special case happens.
574 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
575 in the window and the cx and cy indicate how to size the window.
576 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
577 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
581 GetClientRect(hwndParentDlg, &rectParent);
583 /* when arranging controls we have to use fixed parent size */
584 rectParent.bottom -= help_fixup;
586 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
587 if (hwndStc32)
589 GetWindowRect(hwndStc32, &rectStc32);
590 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
592 /* set the size of the stc32 control according to the size of
593 * client area of the parent dialog
595 SetWindowPos(hwndStc32, 0,
596 0, 0,
597 rectParent.right, rectParent.bottom,
598 SWP_NOMOVE | SWP_NOZORDER);
600 else
601 SetRectEmpty(&rectStc32);
603 /* this part moves controls of the child dialog */
604 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
605 while (hwndChild)
607 if (hwndChild != hwndStc32)
609 GetWindowRect(hwndChild, &rectChild);
610 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
612 /* move only if stc32 exist */
613 if (hwndStc32 && rectChild.left > rectStc32.right)
615 LONG old_left = rectChild.left;
617 /* move to the right of visible controls of the parent dialog */
618 rectChild.left += rectParent.right;
619 rectChild.left -= rectStc32.right;
621 child_width_fixup = rectChild.left - old_left;
623 /* move even if stc32 doesn't exist */
624 if (rectChild.top >= rectStc32.bottom)
626 LONG old_top = rectChild.top;
628 /* move below visible controls of the parent dialog */
629 rectChild.top += rectParent.bottom;
630 rectChild.top -= rectStc32.bottom - rectStc32.top;
632 child_height_fixup = rectChild.top - old_top;
635 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
636 0, 0, SWP_NOSIZE | SWP_NOZORDER);
638 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
641 /* this part moves controls of the parent dialog */
642 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
643 while (hwndChild)
645 if (hwndChild != hwndChildDlg)
647 GetWindowRect(hwndChild, &rectChild);
648 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
650 /* left,top of stc32 marks the position of controls
651 * from the parent dialog
653 rectChild.left += rectStc32.left;
654 rectChild.top += rectStc32.top;
656 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
657 0, 0, SWP_NOSIZE | SWP_NOZORDER);
659 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
662 /* calculate the size of the resulting dialog */
664 /* here we have to use original parent size */
665 GetClientRect(hwndParentDlg, &rectParent);
666 GetClientRect(hwndChildDlg, &rectChild);
668 if (hwndStc32)
670 rectChild.right += child_width_fixup;
671 rectChild.bottom += child_height_fixup;
673 if (rectParent.right > rectChild.right)
675 rectParent.right += rectChild.right;
676 rectParent.right -= rectStc32.right - rectStc32.left;
678 else
680 rectParent.right = rectChild.right;
683 if (rectParent.bottom > rectChild.bottom)
685 rectParent.bottom += rectChild.bottom;
686 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
688 else
690 /* child dialog is higher, unconditionally set new dialog
691 * height to its size (help_fixup will be subtracted below)
693 rectParent.bottom = rectChild.bottom + help_fixup;
696 else
698 rectParent.bottom += rectChild.bottom;
701 /* finally use fixed parent size */
702 rectParent.bottom -= help_fixup;
704 /* set the size of the parent dialog */
705 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
706 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
707 SetWindowPos(hwndParentDlg, 0,
708 0, 0,
709 rectParent.right - rectParent.left,
710 rectParent.bottom - rectParent.top,
711 SWP_NOMOVE | SWP_NOZORDER);
714 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
716 switch(uMsg) {
717 case WM_INITDIALOG:
718 return TRUE;
720 return FALSE;
723 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
725 LPCVOID template;
726 HRSRC hRes;
727 HANDLE hDlgTmpl = 0;
728 HWND hChildDlg = 0;
730 TRACE("\n");
733 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
734 * structure's hInstance parameter is not a HINSTANCE, but
735 * instead a pointer to a template resource to use.
737 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
739 HINSTANCE hinst;
740 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
742 hinst = COMDLG32_hInstance;
743 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
745 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
746 return NULL;
749 else
751 hinst = fodInfos->ofnInfos->hInstance;
752 if(fodInfos->unicode)
754 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
755 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
757 else
759 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
760 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
762 if (!hRes)
764 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
765 return NULL;
767 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
768 !(template = LockResource( hDlgTmpl )))
770 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
771 return NULL;
774 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
775 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
776 (LPARAM)fodInfos->ofnInfos);
777 if(hChildDlg)
779 ShowWindow(hChildDlg,SW_SHOW);
780 return hChildDlg;
783 else if( IsHooked(fodInfos))
785 RECT rectHwnd;
786 struct {
787 DLGTEMPLATE tmplate;
788 WORD menu,class,title;
789 } temp;
790 GetClientRect(hwnd,&rectHwnd);
791 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
792 temp.tmplate.dwExtendedStyle = 0;
793 temp.tmplate.cdit = 0;
794 temp.tmplate.x = 0;
795 temp.tmplate.y = 0;
796 temp.tmplate.cx = 0;
797 temp.tmplate.cy = 0;
798 temp.menu = temp.class = temp.title = 0;
800 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
801 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
803 return hChildDlg;
805 return NULL;
808 /***********************************************************************
809 * SendCustomDlgNotificationMessage
811 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
814 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
816 LRESULT hook_result = 0;
818 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
820 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
822 if(!fodInfos) return 0;
824 if(fodInfos->DlgInfos.hwndCustomDlg)
826 TRACE("CALL NOTIFY for %x\n", uCode);
827 if(fodInfos->unicode)
829 OFNOTIFYW ofnNotify;
830 ofnNotify.hdr.hwndFrom=hwndParentDlg;
831 ofnNotify.hdr.idFrom=0;
832 ofnNotify.hdr.code = uCode;
833 ofnNotify.lpOFN = fodInfos->ofnInfos;
834 ofnNotify.pszFile = NULL;
835 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
837 else
839 OFNOTIFYA ofnNotify;
840 ofnNotify.hdr.hwndFrom=hwndParentDlg;
841 ofnNotify.hdr.idFrom=0;
842 ofnNotify.hdr.code = uCode;
843 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
844 ofnNotify.pszFile = NULL;
845 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
847 TRACE("RET NOTIFY\n");
849 TRACE("Retval: 0x%08lx\n", hook_result);
850 return hook_result;
853 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer)
855 UINT sizeUsed = 0, n, total;
856 LPWSTR lpstrFileList = NULL;
857 WCHAR lpstrCurrentDir[MAX_PATH];
858 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
860 TRACE("CDM_GETFILEPATH:\n");
862 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
863 return -1;
865 /* get path and filenames */
866 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrCurrentDir);
867 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
869 TRACE("path >%s< filespec >%s< %d files\n",
870 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
872 if( fodInfos->unicode )
874 LPWSTR bufW = buffer;
875 total = strlenW(lpstrCurrentDir) + 1 + sizeUsed;
877 /* Prepend the current path */
878 n = strlenW(lpstrCurrentDir) + 1;
879 memcpy( bufW, lpstrCurrentDir, min(n,size) * sizeof(WCHAR));
880 if(n<size)
882 /* 'n' includes trailing \0 */
883 bufW[n-1] = '\\';
884 memcpy( &bufW[n], lpstrFileList, (size-n)*sizeof(WCHAR) );
886 TRACE("returned -> %s\n",debugstr_wn(bufW, total));
888 else
890 LPSTR bufA = buffer;
891 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
892 NULL, 0, NULL, NULL);
893 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
894 NULL, 0, NULL, NULL);
896 /* Prepend the current path */
897 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
898 bufA, size, NULL, NULL);
900 if(n<size)
902 /* 'n' includes trailing \0 */
903 bufA[n-1] = '\\';
904 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
905 &bufA[n], size-n, NULL, NULL);
908 TRACE("returned -> %s\n",debugstr_an(bufA, total));
910 MemFree(lpstrFileList);
912 return total;
915 static INT_PTR FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer)
917 UINT sizeUsed = 0;
918 LPWSTR lpstrFileList = NULL;
919 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
921 TRACE("CDM_GETSPEC:\n");
923 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
924 if( fodInfos->unicode )
926 LPWSTR bufW = buffer;
927 memcpy( bufW, lpstrFileList, sizeof(WCHAR)*sizeUsed );
929 else
931 LPSTR bufA = buffer;
932 sizeUsed = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed,
933 NULL, 0, NULL, NULL);
934 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
935 bufA, size, NULL, NULL);
937 MemFree(lpstrFileList);
939 return sizeUsed;
942 /***********************************************************************
943 * FILEDLG95_HandleCustomDialogMessages
945 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
947 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
949 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
950 WCHAR lpstrPath[MAX_PATH];
951 INT_PTR retval;
953 if(!fodInfos) return FALSE;
955 switch(uMsg)
957 case CDM_GETFILEPATH:
958 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
959 break;
961 case CDM_GETFOLDERPATH:
962 TRACE("CDM_GETFOLDERPATH:\n");
963 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
964 if (lParam)
966 if (fodInfos->unicode)
967 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
968 else
969 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
970 (LPSTR)lParam, (int)wParam, NULL, NULL);
972 retval = strlenW(lpstrPath);
973 break;
975 case CDM_GETSPEC:
976 retval = FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
977 break;
979 case CDM_SETCONTROLTEXT:
980 TRACE("CDM_SETCONTROLTEXT:\n");
981 if ( lParam )
983 if( fodInfos->unicode )
984 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
985 else
986 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
988 retval = TRUE;
989 break;
991 case CDM_HIDECONTROL:
992 /* MSDN states that it should fail for not OFN_EXPLORER case */
993 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
995 HWND control = GetDlgItem( hwnd, wParam );
996 if (control) ShowWindow( control, SW_HIDE );
997 retval = TRUE;
999 else retval = FALSE;
1000 break;
1002 default:
1003 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1004 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1005 return FALSE;
1007 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1008 return TRUE;
1011 /***********************************************************************
1012 * FileOpenDlgProc95
1014 * File open dialog procedure
1016 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1018 #if 0
1019 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
1020 #endif
1022 switch(uMsg)
1024 case WM_INITDIALOG:
1026 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1028 /* Adds the FileOpenDlgInfos in the property list of the dialog
1029 so it will be easily accessible through a GetPropA(...) */
1030 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
1032 fodInfos->DlgInfos.hwndCustomDlg =
1033 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1035 FILEDLG95_InitControls(hwnd);
1037 if (fodInfos->DlgInfos.hwndCustomDlg)
1039 RECT rc;
1040 UINT flags = SWP_NOACTIVATE;
1042 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1043 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1045 /* resize the custom dialog to the parent size */
1046 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1047 GetClientRect(hwnd, &rc);
1048 else
1050 /* our own fake template is zero sized and doesn't have
1051 * children, so there is no need to resize it.
1052 * Picasa depends on it.
1054 flags |= SWP_NOSIZE;
1055 SetRectEmpty(&rc);
1057 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1058 0, 0, rc.right, rc.bottom, flags);
1061 FILEDLG95_FillControls(hwnd, wParam, lParam);
1063 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1064 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1065 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1066 return 0;
1068 case WM_COMMAND:
1069 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1070 case WM_DRAWITEM:
1072 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1074 case IDC_LOOKIN:
1075 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1076 return TRUE;
1079 return FALSE;
1081 case WM_GETISHELLBROWSER:
1082 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1084 case WM_DESTROY:
1085 RemovePropA(hwnd, FileOpenDlgInfosStr);
1086 return FALSE;
1088 case WM_NOTIFY:
1090 LPNMHDR lpnmh = (LPNMHDR)lParam;
1091 UINT stringId = -1;
1093 /* set up the button tooltips strings */
1094 if(TTN_GETDISPINFOA == lpnmh->code )
1096 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1097 switch(lpnmh->idFrom )
1099 /* Up folder button */
1100 case FCIDM_TB_UPFOLDER:
1101 stringId = IDS_UPFOLDER;
1102 break;
1103 /* New folder button */
1104 case FCIDM_TB_NEWFOLDER:
1105 stringId = IDS_NEWFOLDER;
1106 break;
1107 /* List option button */
1108 case FCIDM_TB_SMALLICON:
1109 stringId = IDS_LISTVIEW;
1110 break;
1111 /* Details option button */
1112 case FCIDM_TB_REPORTVIEW:
1113 stringId = IDS_REPORTVIEW;
1114 break;
1115 /* Desktop button */
1116 case FCIDM_TB_DESKTOP:
1117 stringId = IDS_TODESKTOP;
1118 break;
1119 default:
1120 stringId = 0;
1122 lpdi->hinst = COMDLG32_hInstance;
1123 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1125 return FALSE;
1127 default :
1128 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1129 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1130 return FALSE;
1134 /***********************************************************************
1135 * FILEDLG95_InitControls
1137 * WM_INITDIALOG message handler (before hook notification)
1139 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1141 int win2000plus = 0;
1142 int win98plus = 0;
1143 int handledPath = FALSE;
1144 OSVERSIONINFOA osVi;
1145 static const WCHAR szwSlash[] = { '\\', 0 };
1146 static const WCHAR szwStar[] = { '*',0 };
1148 TBBUTTON tbb[] =
1150 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1151 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1152 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1153 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1154 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1155 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1156 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1157 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1158 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1160 TBADDBITMAP tba[2];
1161 RECT rectTB;
1162 RECT rectlook;
1163 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1165 tba[0].hInst = HINST_COMMCTRL;
1166 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1167 tba[1].hInst = COMDLG32_hInstance;
1168 tba[1].nID = 800;
1170 TRACE("%p\n", fodInfos);
1172 /* Get windows version emulating */
1173 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1174 GetVersionExA(&osVi);
1175 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1176 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1177 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1178 win2000plus = (osVi.dwMajorVersion > 4);
1179 if (win2000plus) win98plus = TRUE;
1181 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1183 /* Get the hwnd of the controls */
1184 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1185 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1186 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1188 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1189 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1191 /* construct the toolbar */
1192 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1193 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1195 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1196 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1197 rectTB.left = rectlook.right;
1198 rectTB.top = rectlook.top-1;
1200 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1201 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1202 rectTB.left, rectTB.top,
1203 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1204 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1206 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1208 /* FIXME: use TB_LOADIMAGES when implemented */
1209 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1210 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1211 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1213 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1214 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1216 /* Set the window text with the text specified in the OPENFILENAME structure */
1217 if(fodInfos->title)
1219 SetWindowTextW(hwnd,fodInfos->title);
1221 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1223 WCHAR buf[16];
1224 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1225 SetWindowTextW(hwnd, buf);
1228 /* Initialise the file name edit control */
1229 handledPath = FALSE;
1230 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1232 if(fodInfos->filename)
1234 /* 1. If win2000 or higher and filename contains a path, use it
1235 in preference over the lpstrInitialDir */
1236 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1237 WCHAR tmpBuf[MAX_PATH];
1238 WCHAR *nameBit;
1239 DWORD result;
1241 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1242 if (result) {
1244 /* nameBit is always shorter than the original filename */
1245 strcpyW(fodInfos->filename,nameBit);
1247 *nameBit = 0x00;
1248 if (fodInfos->initdir == NULL)
1249 MemFree(fodInfos->initdir);
1250 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1251 strcpyW(fodInfos->initdir, tmpBuf);
1252 handledPath = TRUE;
1253 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1254 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1256 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1258 } else {
1259 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1263 /* 2. (All platforms) If initdir is not null, then use it */
1264 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1265 (*fodInfos->initdir!=0x00))
1267 /* Work out the proper path as supplied one might be relative */
1268 /* (Here because supplying '.' as dir browses to My Computer) */
1269 if (handledPath==FALSE) {
1270 WCHAR tmpBuf[MAX_PATH];
1271 WCHAR tmpBuf2[MAX_PATH];
1272 WCHAR *nameBit;
1273 DWORD result;
1275 strcpyW(tmpBuf, fodInfos->initdir);
1276 if( PathFileExistsW(tmpBuf) ) {
1277 /* initdir does not have to be a directory. If a file is
1278 * specified, the dir part is taken */
1279 if( PathIsDirectoryW(tmpBuf)) {
1280 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1281 strcatW(tmpBuf, szwSlash);
1283 strcatW(tmpBuf, szwStar);
1285 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1286 if (result) {
1287 *nameBit = 0x00;
1288 if (fodInfos->initdir)
1289 MemFree(fodInfos->initdir);
1290 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1291 strcpyW(fodInfos->initdir, tmpBuf2);
1292 handledPath = TRUE;
1294 * This is a picasa change to help resolve link issues
1295 * this allows the file open dialog which starts in My Pictures
1296 * to not have a long path into C: as its startup location
1299 LPSTR path;
1300 char real_path[1024];
1302 path = wine_get_unix_file_name(fodInfos->initdir);
1303 realpath(path,real_path);
1304 fodInfos->initdir = wine_get_dos_file_name(real_path);
1305 MemFree(path);
1308 * end Picasa change
1310 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1313 else if (fodInfos->initdir)
1315 MemFree(fodInfos->initdir);
1316 fodInfos->initdir = NULL;
1317 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1322 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1323 (*fodInfos->initdir==0x00)))
1325 /* 3. All except w2k+: if filename contains a path use it */
1326 if (!win2000plus && fodInfos->filename &&
1327 *fodInfos->filename &&
1328 strpbrkW(fodInfos->filename, szwSlash)) {
1329 WCHAR tmpBuf[MAX_PATH];
1330 WCHAR *nameBit;
1331 DWORD result;
1333 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1334 tmpBuf, &nameBit);
1335 if (result) {
1336 int len;
1338 /* nameBit is always shorter than the original filename */
1339 strcpyW(fodInfos->filename, nameBit);
1340 *nameBit = 0x00;
1342 len = strlenW(tmpBuf);
1343 if(fodInfos->initdir)
1344 MemFree(fodInfos->initdir);
1345 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1346 strcpyW(fodInfos->initdir, tmpBuf);
1348 handledPath = TRUE;
1349 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1350 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1352 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1355 /* 4. win98+ and win2000+ if any files of specified filter types in
1356 current directory, use it */
1357 if ( win98plus && handledPath == FALSE &&
1358 fodInfos->filter && *fodInfos->filter) {
1360 BOOL searchMore = TRUE;
1361 LPCWSTR lpstrPos = fodInfos->filter;
1362 WIN32_FIND_DATAW FindFileData;
1363 HANDLE hFind;
1365 while (searchMore)
1367 /* filter is a list... title\0ext\0......\0\0 */
1369 /* Skip the title */
1370 if(! *lpstrPos) break; /* end */
1371 lpstrPos += strlenW(lpstrPos) + 1;
1373 /* See if any files exist in the current dir with this extension */
1374 if(! *lpstrPos) break; /* end */
1376 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1378 if (hFind == INVALID_HANDLE_VALUE) {
1379 /* None found - continue search */
1380 lpstrPos += strlenW(lpstrPos) + 1;
1382 } else {
1383 searchMore = FALSE;
1385 if(fodInfos->initdir)
1386 MemFree(fodInfos->initdir);
1387 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1388 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1390 handledPath = TRUE;
1391 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1392 debugstr_w(lpstrPos));
1393 break;
1398 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1400 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1401 if (handledPath == FALSE && (win2000plus || win98plus)) {
1402 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1404 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1406 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1408 /* last fallback */
1409 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1410 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1411 } else {
1412 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1414 } else {
1415 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1417 handledPath = TRUE;
1418 } else if (handledPath==FALSE) {
1419 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1420 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1421 handledPath = TRUE;
1422 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1425 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1426 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1428 /* Must the open as read only check box be checked ?*/
1429 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1431 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1434 /* Must the open as read only check box be hidden? */
1435 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1437 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1438 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1441 /* Must the help button be hidden? */
1442 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1444 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1445 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1448 /* Resize the height, if open as read only checkbox ad help button
1449 are hidden and we are not using a custom template nor a customDialog
1451 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1452 (!(fodInfos->ofnInfos->Flags &
1453 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1454 (!fodInfos->DlgInfos.hwndCustomDlg ))
1456 RECT rectDlg, rectHelp, rectCancel;
1457 GetWindowRect(hwnd, &rectDlg);
1458 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1459 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1460 /* subtract the height of the help button plus the space between
1461 the help button and the cancel button to the height of the dialog */
1462 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1463 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1464 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1466 /* change Open to Save */
1467 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1469 WCHAR buf[16];
1470 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1471 SetDlgItemTextW(hwnd, IDOK, buf);
1472 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1473 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1475 return 0;
1478 /***********************************************************************
1479 * FILEDLG95_FillControls
1481 * WM_INITDIALOG message handler (after hook notification)
1483 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1485 LPITEMIDLIST pidlItemId = NULL;
1487 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1489 TRACE("dir=%s file=%s\n",
1490 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1492 /* Get the initial directory pidl */
1494 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1496 WCHAR path[MAX_PATH];
1498 GetCurrentDirectoryW(MAX_PATH,path);
1499 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1502 /* Initialise shell objects */
1503 FILEDLG95_SHELL_Init(hwnd);
1505 /* Initialize the Look In combo box */
1506 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1508 /* Initialize the filter combo box */
1509 FILEDLG95_FILETYPE_Init(hwnd);
1511 /* Browse to the initial directory */
1512 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1514 /* Free pidlItem memory */
1515 COMDLG32_SHFree(pidlItemId);
1517 return TRUE;
1519 /***********************************************************************
1520 * FILEDLG95_Clean
1522 * Regroups all the cleaning functions of the filedlg
1524 void FILEDLG95_Clean(HWND hwnd)
1526 FILEDLG95_FILETYPE_Clean(hwnd);
1527 FILEDLG95_LOOKIN_Clean(hwnd);
1528 FILEDLG95_SHELL_Clean(hwnd);
1530 /***********************************************************************
1531 * FILEDLG95_OnWMCommand
1533 * WM_COMMAND message handler
1535 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1537 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1538 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1539 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1541 switch(wID)
1543 /* OK button */
1544 case IDOK:
1545 FILEDLG95_OnOpen(hwnd);
1546 break;
1547 /* Cancel button */
1548 case IDCANCEL:
1549 FILEDLG95_Clean(hwnd);
1550 EndDialog(hwnd, FALSE);
1551 break;
1552 /* Filetype combo box */
1553 case IDC_FILETYPE:
1554 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1555 break;
1556 /* LookIn combo box */
1557 case IDC_LOOKIN:
1558 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1559 break;
1561 /* --- toolbar --- */
1562 /* Up folder button */
1563 case FCIDM_TB_UPFOLDER:
1564 FILEDLG95_SHELL_UpFolder(hwnd);
1565 break;
1566 /* New folder button */
1567 case FCIDM_TB_NEWFOLDER:
1568 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1569 break;
1570 /* List option button */
1571 case FCIDM_TB_SMALLICON:
1572 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1573 break;
1574 /* Details option button */
1575 case FCIDM_TB_REPORTVIEW:
1576 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1577 break;
1578 /* Details option button */
1579 case FCIDM_TB_DESKTOP:
1580 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1581 break;
1583 case IDC_FILENAME:
1584 break;
1587 /* Do not use the listview selection anymore */
1588 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1589 return 0;
1592 /***********************************************************************
1593 * FILEDLG95_OnWMGetIShellBrowser
1595 * WM_GETISHELLBROWSER message handler
1597 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1600 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1602 TRACE("\n");
1604 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1606 return TRUE;
1610 /***********************************************************************
1611 * FILEDLG95_SendFileOK
1613 * Sends the CDN_FILEOK notification if required
1615 * RETURNS
1616 * TRUE if the dialog should close
1617 * FALSE if the dialog should not be closed
1619 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1621 /* ask the hook if we can close */
1622 if(IsHooked(fodInfos))
1624 LRESULT retval;
1626 TRACE("---\n");
1627 /* First send CDN_FILEOK as MSDN doc says */
1628 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1629 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1631 TRACE("canceled\n");
1632 return (retval == 0);
1635 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1636 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1637 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1638 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1640 TRACE("canceled\n");
1641 return (retval == 0);
1644 return TRUE;
1647 /***********************************************************************
1648 * FILEDLG95_OnOpenMultipleFiles
1650 * Handles the opening of multiple files.
1652 * FIXME
1653 * check destination buffer size
1655 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1657 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1658 UINT nCount, nSizePath;
1659 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1661 TRACE("\n");
1663 if(fodInfos->unicode)
1665 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1666 ofn->lpstrFile[0] = '\0';
1668 else
1670 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1671 ofn->lpstrFile[0] = '\0';
1674 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1676 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1677 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1678 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1680 LPWSTR lpstrTemp = lpstrFileList;
1682 for ( nCount = 0; nCount < nFileCount; nCount++ )
1684 LPITEMIDLIST pidl;
1686 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1687 if (!pidl)
1689 WCHAR lpstrNotFound[100];
1690 WCHAR lpstrMsg[100];
1691 WCHAR tmp[400];
1692 static const WCHAR nl[] = {'\n',0};
1694 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1695 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1697 strcpyW(tmp, lpstrTemp);
1698 strcatW(tmp, nl);
1699 strcatW(tmp, lpstrNotFound);
1700 strcatW(tmp, nl);
1701 strcatW(tmp, lpstrMsg);
1703 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1704 return FALSE;
1707 /* move to the next file in the list of files */
1708 lpstrTemp += strlenW(lpstrTemp) + 1;
1709 COMDLG32_SHFree(pidl);
1713 nSizePath = strlenW(lpstrPathSpec) + 1;
1714 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1716 /* For "oldstyle" dialog the components have to
1717 be separated by blanks (not '\0'!) and short
1718 filenames have to be used! */
1719 FIXME("Components have to be separated by blanks\n");
1721 if(fodInfos->unicode)
1723 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1724 if (nSizePath+sizeUsed > ofn->nMaxFile)
1726 *((WORD*)ofn->lpstrFile)=nSizePath+sizeUsed;
1727 FILEDLG95_Clean(hwnd);
1728 EndDialog(hwnd,FALSE);
1729 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
1730 return FALSE;
1732 else
1734 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1735 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1738 else
1740 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1742 if (ofn->lpstrFile != NULL)
1744 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1745 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1746 if (ofn->nMaxFile > nSizePath)
1748 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1749 ofn->lpstrFile + nSizePath,
1750 ofn->nMaxFile - nSizePath, NULL, NULL);
1755 fodInfos->ofnInfos->nFileOffset = nSizePath;
1756 fodInfos->ofnInfos->nFileExtension = 0;
1758 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1759 return FALSE;
1761 /* clean and exit */
1762 FILEDLG95_Clean(hwnd);
1763 return EndDialog(hwnd,TRUE);
1766 /***********************************************************************
1767 * FILEDLG95_OnOpen
1769 * Ok button WM_COMMAND message handler
1771 * If the function succeeds, the return value is nonzero.
1773 #define ONOPEN_BROWSE 1
1774 #define ONOPEN_OPEN 2
1775 #define ONOPEN_SEARCH 3
1776 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1778 WCHAR strMsgTitle[MAX_PATH];
1779 WCHAR strMsgText [MAX_PATH];
1780 if (idCaption)
1781 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1782 else
1783 strMsgTitle[0] = '\0';
1784 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1785 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1788 BOOL FILEDLG95_OnOpen(HWND hwnd)
1790 LPWSTR lpstrFileList;
1791 UINT nFileCount = 0;
1792 UINT sizeUsed = 0;
1793 BOOL ret = TRUE;
1794 WCHAR lpstrPathAndFile[MAX_PATH];
1795 WCHAR lpstrTemp[MAX_PATH];
1796 LPSHELLFOLDER lpsf = NULL;
1797 int nOpenAction;
1798 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1800 TRACE("hwnd=%p\n", hwnd);
1802 /* get the files from the edit control */
1803 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1805 /* try if the user selected a folder in the shellview */
1806 if(nFileCount == 0)
1808 BrowseSelectedFolder(hwnd);
1809 return FALSE;
1812 if(nFileCount > 1)
1814 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1815 goto ret;
1818 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1821 Step 1: Build a complete path name from the current folder and
1822 the filename or path in the edit box.
1823 Special cases:
1824 - the path in the edit box is a root path
1825 (with or without drive letter)
1826 - the edit box contains ".." (or a path with ".." in it)
1829 /* Get the current directory name */
1830 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1832 /* last fallback */
1833 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1835 PathAddBackslashW(lpstrPathAndFile);
1837 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1839 /* if the user specifyed a fully qualified path use it */
1840 if(PathIsRelativeW(lpstrFileList))
1842 strcatW(lpstrPathAndFile, lpstrFileList);
1844 else
1846 /* does the path have a drive letter? */
1847 if (PathGetDriveNumberW(lpstrFileList) == -1)
1848 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1849 else
1850 strcpyW(lpstrPathAndFile, lpstrFileList);
1853 /* resolve "." and ".." */
1854 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1855 strcpyW(lpstrPathAndFile, lpstrTemp);
1856 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1858 MemFree(lpstrFileList);
1861 Step 2: here we have a cleaned up path
1863 We have to parse the path step by step to see if we have to browse
1864 to a folder if the path points to a directory or the last
1865 valid element is a directory.
1867 valid variables:
1868 lpstrPathAndFile: cleaned up path
1871 if (nFileCount &&
1872 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1873 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1874 nOpenAction = ONOPEN_OPEN;
1875 else
1876 nOpenAction = ONOPEN_BROWSE;
1878 /* don't apply any checks with OFN_NOVALIDATE */
1880 LPWSTR lpszTemp, lpszTemp1;
1881 LPITEMIDLIST pidl = NULL;
1882 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1884 /* check for invalid chars */
1885 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1887 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1888 ret = FALSE;
1889 goto ret;
1892 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1894 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1895 while (lpszTemp1)
1897 LPSHELLFOLDER lpsfChild;
1898 WCHAR lpwstrTemp[MAX_PATH];
1899 DWORD dwEaten, dwAttributes;
1900 LPWSTR p;
1902 strcpyW(lpwstrTemp, lpszTemp);
1903 p = PathFindNextComponentW(lpwstrTemp);
1905 if (!p) break; /* end of path */
1907 *p = 0;
1908 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1910 /* There are no wildcards when OFN_NOVALIDATE is set */
1911 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1913 static const WCHAR wszWild[] = { '*', '?', 0 };
1914 /* if the last element is a wildcard do a search */
1915 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1917 nOpenAction = ONOPEN_SEARCH;
1918 break;
1921 lpszTemp1 = lpszTemp;
1923 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1925 /* append a backslash to drive letters */
1926 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1927 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1928 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1930 PathAddBackslashW(lpwstrTemp);
1933 dwAttributes = SFGAO_FOLDER;
1934 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1936 /* the path component is valid, we have a pidl of the next path component */
1937 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1938 if(dwAttributes & SFGAO_FOLDER)
1940 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1942 ERR("bind to failed\n"); /* should not fail */
1943 break;
1945 IShellFolder_Release(lpsf);
1946 lpsf = lpsfChild;
1947 lpsfChild = NULL;
1949 else
1951 TRACE("value\n");
1953 /* end dialog, return value */
1954 nOpenAction = ONOPEN_OPEN;
1955 break;
1957 COMDLG32_SHFree(pidl);
1958 pidl = NULL;
1960 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1962 if(*lpszTemp) /* points to trailing null for last path element */
1964 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1966 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1967 break;
1970 else
1972 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1973 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1975 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1976 break;
1979 /* change to the current folder */
1980 nOpenAction = ONOPEN_OPEN;
1981 break;
1983 else
1985 nOpenAction = ONOPEN_OPEN;
1986 break;
1989 if(pidl) COMDLG32_SHFree(pidl);
1993 Step 3: here we have a cleaned up and validated path
1995 valid variables:
1996 lpsf: ShellFolder bound to the rightmost valid path component
1997 lpstrPathAndFile: cleaned up path
1998 nOpenAction: action to do
2000 TRACE("end validate sf=%p\n", lpsf);
2002 switch(nOpenAction)
2004 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2005 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2007 int iPos;
2008 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2009 DWORD len;
2011 /* replace the current filter */
2012 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2013 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2014 len = strlenW(lpszTemp)+1;
2015 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2016 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2018 /* set the filter cb to the extension when possible */
2019 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2020 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2022 /* fall through */
2023 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2024 TRACE("ONOPEN_BROWSE\n");
2026 IPersistFolder2 * ppf2;
2027 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2029 LPITEMIDLIST pidlCurrent;
2030 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2031 IPersistFolder2_Release(ppf2);
2032 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2034 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
2036 else if( nOpenAction == ONOPEN_SEARCH )
2038 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2040 COMDLG32_SHFree(pidlCurrent);
2043 ret = FALSE;
2044 break;
2045 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2046 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2048 WCHAR *ext = NULL;
2050 /* update READONLY check box flag */
2051 if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2052 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2053 else
2054 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2056 /* Attach the file extension with file name*/
2057 ext = PathFindExtensionW(lpstrPathAndFile);
2058 if (! *ext)
2060 /* if no extension is specified with file name, then */
2061 /* attach the extension from file filter or default one */
2063 WCHAR *filterExt = NULL;
2064 LPWSTR lpstrFilter = NULL;
2065 static const WCHAR szwDot[] = {'.',0};
2066 int PathLength = strlenW(lpstrPathAndFile);
2068 /* Attach the dot*/
2069 strcatW(lpstrPathAndFile, szwDot);
2071 /*Get the file extension from file type filter*/
2072 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2073 fodInfos->ofnInfos->nFilterIndex-1);
2075 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2076 filterExt = PathFindExtensionW(lpstrFilter);
2078 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2079 strcatW(lpstrPathAndFile, filterExt + 1);
2080 else if ( fodInfos->defext ) /* attach the default file extension*/
2081 strcatW(lpstrPathAndFile, fodInfos->defext);
2083 /* In Open dialog: if file does not exist try without extension */
2084 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2085 lpstrPathAndFile[PathLength] = '\0';
2088 if (fodInfos->defext) /* add default extension */
2090 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2091 if (*ext)
2092 ext++;
2093 if (!lstrcmpiW(fodInfos->defext, ext))
2094 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2095 else
2096 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2099 /* In Save dialog: check if the file already exists */
2100 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2101 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2102 && PathFileExistsW(lpstrPathAndFile))
2104 WCHAR lpstrOverwrite[100];
2105 int answer;
2107 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2108 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2109 MB_YESNO | MB_ICONEXCLAMATION);
2110 if (answer == IDNO)
2112 ret = FALSE;
2113 goto ret;
2117 /* Check that the size of the file does not exceed buffer size.
2118 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2119 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2120 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2122 LPWSTR lpszTemp;
2124 /* fill destination buffer */
2125 if (fodInfos->ofnInfos->lpstrFile)
2127 if(fodInfos->unicode)
2129 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2131 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2132 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2133 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2135 else
2137 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2139 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2140 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2141 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2142 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2146 /* set filename offset */
2147 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2148 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2150 /* set extension offset */
2151 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2152 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2154 /* set the lpstrFileTitle */
2155 if(fodInfos->ofnInfos->lpstrFileTitle)
2157 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2158 if(fodInfos->unicode)
2160 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2161 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2163 else
2165 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2166 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2167 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2171 /* copy currently selected filter to lpstrCustomFilter */
2172 if (fodInfos->ofnInfos->lpstrCustomFilter)
2174 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2175 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2176 NULL, 0, NULL, NULL);
2177 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2179 LPSTR s = ofn->lpstrCustomFilter;
2180 s += strlen(ofn->lpstrCustomFilter)+1;
2181 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2182 s, len, NULL, NULL);
2187 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2188 goto ret;
2190 TRACE("close\n");
2191 FILEDLG95_Clean(hwnd);
2192 ret = EndDialog(hwnd, TRUE);
2194 else
2196 WORD size;
2198 size = strlenW(lpstrPathAndFile) + 1;
2199 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2200 size += 1;
2201 /* return needed size in first two bytes of lpstrFile */
2202 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2203 FILEDLG95_Clean(hwnd);
2204 ret = EndDialog(hwnd, FALSE);
2205 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2207 goto ret;
2209 break;
2212 ret:
2213 if(lpsf) IShellFolder_Release(lpsf);
2214 return ret;
2217 /***********************************************************************
2218 * FILEDLG95_SHELL_Init
2220 * Initialisation of the shell objects
2222 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2224 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2226 TRACE("\n");
2229 * Initialisation of the FileOpenDialogInfos structure
2232 /* Shell */
2234 /*ShellInfos */
2235 fodInfos->ShellInfos.hwndOwner = hwnd;
2237 /* Disable multi-select if flag not set */
2238 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2240 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2242 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2243 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2245 /* Construct the IShellBrowser interface */
2246 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2248 return NOERROR;
2251 /***********************************************************************
2252 * FILEDLG95_SHELL_ExecuteCommand
2254 * Change the folder option and refresh the view
2255 * If the function succeeds, the return value is nonzero.
2257 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2259 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2261 IContextMenu * pcm;
2262 TRACE("(%p,%p)\n", hwnd, lpVerb);
2264 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2265 SVGIO_BACKGROUND,
2266 &IID_IContextMenu,
2267 (LPVOID*)&pcm)))
2269 CMINVOKECOMMANDINFO ci;
2270 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2271 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2272 ci.lpVerb = lpVerb;
2273 ci.hwnd = hwnd;
2275 IContextMenu_InvokeCommand(pcm, &ci);
2276 IContextMenu_Release(pcm);
2279 return FALSE;
2282 /***********************************************************************
2283 * FILEDLG95_SHELL_UpFolder
2285 * Browse to the specified object
2286 * If the function succeeds, the return value is nonzero.
2288 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2290 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2292 TRACE("\n");
2294 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2295 NULL,
2296 SBSP_PARENT)))
2298 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2299 return TRUE;
2301 return FALSE;
2304 /***********************************************************************
2305 * FILEDLG95_SHELL_BrowseToDesktop
2307 * Browse to the Desktop
2308 * If the function succeeds, the return value is nonzero.
2310 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2312 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2313 LPITEMIDLIST pidl;
2314 HRESULT hres;
2316 TRACE("\n");
2318 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2319 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2320 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2321 COMDLG32_SHFree(pidl);
2322 return SUCCEEDED(hres);
2324 /***********************************************************************
2325 * FILEDLG95_SHELL_Clean
2327 * Cleans the memory used by shell objects
2329 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2331 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2333 TRACE("\n");
2335 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2337 /* clean Shell interfaces */
2338 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2339 IShellView_Release(fodInfos->Shell.FOIShellView);
2340 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2341 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2342 if (fodInfos->Shell.FOIDataObject)
2343 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2346 /***********************************************************************
2347 * FILEDLG95_FILETYPE_Init
2349 * Initialisation of the file type combo box
2351 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2353 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2354 int nFilters = 0; /* number of filters */
2355 int nFilterIndexCB;
2357 TRACE("\n");
2359 if(fodInfos->customfilter)
2361 /* customfilter has one entry... title\0ext\0
2362 * Set first entry of combo box item with customfilter
2364 LPWSTR lpstrExt;
2365 LPCWSTR lpstrPos = fodInfos->customfilter;
2367 /* Get the title */
2368 lpstrPos += strlenW(fodInfos->customfilter) + 1;
2370 /* Copy the extensions */
2371 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2372 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2373 strcpyW(lpstrExt,lpstrPos);
2375 /* Add the item at the end of the combo */
2376 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2377 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2378 nFilters++;
2380 if(fodInfos->filter)
2382 LPCWSTR lpstrPos = fodInfos->filter;
2384 for(;;)
2386 /* filter is a list... title\0ext\0......\0\0
2387 * Set the combo item text to the title and the item data
2388 * to the ext
2390 LPCWSTR lpstrDisplay;
2391 LPWSTR lpstrExt;
2393 /* Get the title */
2394 if(! *lpstrPos) break; /* end */
2395 lpstrDisplay = lpstrPos;
2396 lpstrPos += strlenW(lpstrPos) + 1;
2398 /* Copy the extensions */
2399 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2400 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2401 strcpyW(lpstrExt,lpstrPos);
2402 lpstrPos += strlenW(lpstrPos) + 1;
2404 /* Add the item at the end of the combo */
2405 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2406 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2407 nFilters++;
2412 * Set the current filter to the one specified
2413 * in the initialisation structure
2415 if (fodInfos->filter || fodInfos->customfilter)
2417 LPWSTR lpstrFilter;
2419 /* Check to make sure our index isn't out of bounds. */
2420 if ( fodInfos->ofnInfos->nFilterIndex >
2421 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2422 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2424 /* set default filter index */
2425 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2426 fodInfos->ofnInfos->nFilterIndex = 1;
2428 /* calculate index of Combo Box item */
2429 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2430 if (fodInfos->customfilter == NULL)
2431 nFilterIndexCB--;
2433 /* Set the current index selection. */
2434 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2436 /* Get the corresponding text string from the combo box. */
2437 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2438 nFilterIndexCB);
2440 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2441 lpstrFilter = NULL;
2443 if(lpstrFilter)
2445 DWORD len;
2446 CharLowerW(lpstrFilter); /* lowercase */
2447 len = strlenW(lpstrFilter)+1;
2448 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2449 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2451 } else
2452 fodInfos->ofnInfos->nFilterIndex = 0;
2453 return S_OK;
2456 /***********************************************************************
2457 * FILEDLG95_FILETYPE_OnCommand
2459 * WM_COMMAND of the file type combo box
2460 * If the function succeeds, the return value is nonzero.
2462 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2464 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2466 switch(wNotifyCode)
2468 case CBN_SELENDOK:
2470 LPWSTR lpstrFilter;
2472 /* Get the current item of the filetype combo box */
2473 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2475 /* set the current filter index */
2476 fodInfos->ofnInfos->nFilterIndex = iItem +
2477 (fodInfos->customfilter == NULL ? 1 : 0);
2479 /* Set the current filter with the current selection */
2480 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2481 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2483 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2484 iItem);
2485 if((INT_PTR)lpstrFilter != CB_ERR)
2487 DWORD len;
2488 CharLowerW(lpstrFilter); /* lowercase */
2489 len = strlenW(lpstrFilter)+1;
2490 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2491 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2492 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2495 /* Refresh the actual view to display the included items*/
2496 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2499 return FALSE;
2501 /***********************************************************************
2502 * FILEDLG95_FILETYPE_SearchExt
2504 * searches for an extension in the filetype box
2506 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2508 int i, iCount = CBGetCount(hwnd);
2510 TRACE("%s\n", debugstr_w(lpstrExt));
2512 if(iCount != CB_ERR)
2514 for(i=0;i<iCount;i++)
2516 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2517 return i;
2520 return -1;
2523 /***********************************************************************
2524 * FILEDLG95_FILETYPE_Clean
2526 * Clean the memory used by the filetype combo box
2528 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2530 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2531 int iPos;
2532 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2534 TRACE("\n");
2536 /* Delete each string of the combo and their associated data */
2537 if(iCount != CB_ERR)
2539 for(iPos = iCount-1;iPos>=0;iPos--)
2541 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2542 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2545 /* Current filter */
2546 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2547 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2551 /***********************************************************************
2552 * FILEDLG95_LOOKIN_Init
2554 * Initialisation of the look in combo box
2557 /* Small helper function, to determine if the unixfs shell extension is rooted
2558 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2560 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2561 HKEY hKey;
2562 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2563 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2564 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2565 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2566 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2567 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2568 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2570 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2571 return FALSE;
2573 RegCloseKey(hKey);
2574 return TRUE;
2577 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2579 IShellFolder *psfRoot, *psfDrives;
2580 IEnumIDList *lpeRoot, *lpeDrives;
2581 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2583 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2585 TRACE("\n");
2587 liInfos->iMaxIndentation = 0;
2589 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2591 /* set item height for both text field and listbox */
2592 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2593 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2595 /* Turn on the extended UI for the combo box like Windows does */
2596 CBSetExtendedUI(hwndCombo, TRUE);
2598 /* Initialise data of Desktop folder */
2599 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2600 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2601 COMDLG32_SHFree(pidlTmp);
2603 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2605 SHGetDesktopFolder(&psfRoot);
2607 if (psfRoot)
2609 /* enumerate the contents of the desktop */
2610 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2612 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2614 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2616 /* If the unixfs extension is rooted, we don't expand the drives by default */
2617 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2619 /* special handling for CSIDL_DRIVES */
2620 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2622 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2624 /* enumerate the drives */
2625 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2627 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2629 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2630 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2631 COMDLG32_SHFree(pidlAbsTmp);
2632 COMDLG32_SHFree(pidlTmp1);
2634 IEnumIDList_Release(lpeDrives);
2636 IShellFolder_Release(psfDrives);
2641 COMDLG32_SHFree(pidlTmp);
2643 IEnumIDList_Release(lpeRoot);
2645 IShellFolder_Release(psfRoot);
2648 COMDLG32_SHFree(pidlDrives);
2651 /***********************************************************************
2652 * FILEDLG95_LOOKIN_DrawItem
2654 * WM_DRAWITEM message handler
2656 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2658 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2659 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2660 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2661 RECT rectText;
2662 RECT rectIcon;
2663 SHFILEINFOA sfi;
2664 HIMAGELIST ilItemImage;
2665 int iIndentation;
2666 TEXTMETRICA tm;
2667 LPSFOLDER tmpFolder;
2670 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2672 TRACE("\n");
2674 if(pDIStruct->itemID == -1)
2675 return 0;
2677 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2678 pDIStruct->itemID)))
2679 return 0;
2682 if(pDIStruct->itemID == liInfos->uSelectedItem)
2684 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2686 &sfi,
2687 sizeof (SHFILEINFOA),
2688 SHGFI_PIDL | SHGFI_SMALLICON |
2689 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2690 SHGFI_DISPLAYNAME );
2692 else
2694 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2696 &sfi,
2697 sizeof (SHFILEINFOA),
2698 SHGFI_PIDL | SHGFI_SMALLICON |
2699 SHGFI_SYSICONINDEX |
2700 SHGFI_DISPLAYNAME);
2703 /* Is this item selected ? */
2704 if(pDIStruct->itemState & ODS_SELECTED)
2706 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2707 SetBkColor(pDIStruct->hDC,crHighLight);
2708 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2710 else
2712 SetTextColor(pDIStruct->hDC,crText);
2713 SetBkColor(pDIStruct->hDC,crWin);
2714 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2717 /* Do not indent item if drawing in the edit of the combo */
2718 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2720 iIndentation = 0;
2721 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2723 &sfi,
2724 sizeof (SHFILEINFOA),
2725 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2726 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2729 else
2731 iIndentation = tmpFolder->m_iIndent;
2733 /* Draw text and icon */
2735 /* Initialise the icon display area */
2736 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2737 rectIcon.top = pDIStruct->rcItem.top;
2738 rectIcon.right = rectIcon.left + ICONWIDTH;
2739 rectIcon.bottom = pDIStruct->rcItem.bottom;
2741 /* Initialise the text display area */
2742 GetTextMetricsA(pDIStruct->hDC, &tm);
2743 rectText.left = rectIcon.right;
2744 rectText.top =
2745 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2746 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2747 rectText.bottom =
2748 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2750 /* Draw the icon from the image list */
2751 ImageList_Draw(ilItemImage,
2752 sfi.iIcon,
2753 pDIStruct->hDC,
2754 rectIcon.left,
2755 rectIcon.top,
2756 ILD_TRANSPARENT );
2758 /* Draw the associated text */
2759 if(sfi.szDisplayName)
2760 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2763 return NOERROR;
2766 /***********************************************************************
2767 * FILEDLG95_LOOKIN_OnCommand
2769 * LookIn combo box WM_COMMAND message handler
2770 * If the function succeeds, the return value is nonzero.
2772 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2774 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2776 TRACE("%p\n", fodInfos);
2778 switch(wNotifyCode)
2780 case CBN_SELENDOK:
2782 LPSFOLDER tmpFolder;
2783 int iItem;
2785 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2787 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2788 iItem)))
2789 return FALSE;
2792 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2793 tmpFolder->pidlItem,
2794 SBSP_ABSOLUTE)))
2796 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2797 return TRUE;
2799 break;
2803 return FALSE;
2806 /***********************************************************************
2807 * FILEDLG95_LOOKIN_AddItem
2809 * Adds an absolute pidl item to the lookin combo box
2810 * returns the index of the inserted item
2812 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2814 LPITEMIDLIST pidlNext;
2815 SHFILEINFOA sfi;
2816 SFOLDER *tmpFolder;
2817 LookInInfos *liInfos;
2819 TRACE("%08x\n", iInsertId);
2821 if(!pidl)
2822 return -1;
2824 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2825 return -1;
2827 tmpFolder = MemAlloc(sizeof(SFOLDER));
2828 tmpFolder->m_iIndent = 0;
2830 /* Calculate the indentation of the item in the lookin*/
2831 pidlNext = pidl;
2832 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2834 tmpFolder->m_iIndent++;
2837 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2839 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2840 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2842 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2843 SHGetFileInfoA((LPSTR)pidl,
2845 &sfi,
2846 sizeof(sfi),
2847 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2848 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2850 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2852 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2854 int iItemID;
2856 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2858 /* Add the item at the end of the list */
2859 if(iInsertId < 0)
2861 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2863 /* Insert the item at the iInsertId position*/
2864 else
2866 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2869 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2870 return iItemID;
2873 COMDLG32_SHFree( tmpFolder->pidlItem );
2874 MemFree( tmpFolder );
2875 return -1;
2879 /***********************************************************************
2880 * FILEDLG95_LOOKIN_InsertItemAfterParent
2882 * Insert an item below its parent
2884 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2887 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2888 int iParentPos;
2890 TRACE("\n");
2892 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2894 if(iParentPos < 0)
2896 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2899 /* Free pidlParent memory */
2900 COMDLG32_SHFree((LPVOID)pidlParent);
2902 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2905 /***********************************************************************
2906 * FILEDLG95_LOOKIN_SelectItem
2908 * Adds an absolute pidl item to the lookin combo box
2909 * returns the index of the inserted item
2911 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2913 int iItemPos;
2914 LookInInfos *liInfos;
2916 TRACE("\n");
2918 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2920 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2922 if(iItemPos < 0)
2924 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2925 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2928 else
2930 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2931 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2933 int iRemovedItem;
2935 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2936 break;
2937 if(iRemovedItem < iItemPos)
2938 iItemPos--;
2942 CBSetCurSel(hwnd,iItemPos);
2943 liInfos->uSelectedItem = iItemPos;
2945 return 0;
2949 /***********************************************************************
2950 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2952 * Remove the item with an expansion level over iExpansionLevel
2954 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2956 int iItemPos;
2958 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2960 TRACE("\n");
2962 if(liInfos->iMaxIndentation <= 2)
2963 return -1;
2965 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2967 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2968 COMDLG32_SHFree(tmpFolder->pidlItem);
2969 MemFree(tmpFolder);
2970 CBDeleteString(hwnd,iItemPos);
2971 liInfos->iMaxIndentation--;
2973 return iItemPos;
2976 return -1;
2979 /***********************************************************************
2980 * FILEDLG95_LOOKIN_SearchItem
2982 * Search for pidl in the lookin combo box
2983 * returns the index of the found item
2985 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2987 int i = 0;
2988 int iCount = CBGetCount(hwnd);
2990 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2992 if (iCount != CB_ERR)
2994 for(;i<iCount;i++)
2996 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2998 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2999 return i;
3000 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3001 return i;
3005 return -1;
3008 /***********************************************************************
3009 * FILEDLG95_LOOKIN_Clean
3011 * Clean the memory used by the lookin combo box
3013 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3015 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3016 int iPos;
3017 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3019 TRACE("\n");
3021 /* Delete each string of the combo and their associated data */
3022 if (iCount != CB_ERR)
3024 for(iPos = iCount-1;iPos>=0;iPos--)
3026 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3027 COMDLG32_SHFree(tmpFolder->pidlItem);
3028 MemFree(tmpFolder);
3029 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3033 /* LookInInfos structure */
3034 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3037 /***********************************************************************
3038 * FILEDLG95_FILENAME_FillFromSelection
3040 * fills the edit box from the cached DataObject
3042 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3044 FileOpenDlgInfos *fodInfos;
3045 LPITEMIDLIST pidl;
3046 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3047 char lpstrTemp[MAX_PATH];
3048 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
3050 TRACE("\n");
3051 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3053 /* Count how many files we have */
3054 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3056 /* calculate the string length, count files */
3057 if (nFileSelected >= 1)
3059 nLength += 3; /* first and last quotes, trailing \0 */
3060 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3062 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3064 if (pidl)
3066 /* get the total length of the selected file names */
3067 lpstrTemp[0] = '\0';
3068 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3070 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3072 nLength += strlen( lpstrTemp ) + 3;
3073 nFiles++;
3075 COMDLG32_SHFree( pidl );
3080 /* allocate the buffer */
3081 if (nFiles <= 1) nLength = MAX_PATH;
3082 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
3083 lpstrAllFile[0] = '\0';
3085 /* Generate the string for the edit control */
3086 if(nFiles >= 1)
3088 lpstrCurrFile = lpstrAllFile;
3089 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3091 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3093 if (pidl)
3095 /* get the file name */
3096 lpstrTemp[0] = '\0';
3097 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3099 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3101 if ( nFiles > 1)
3103 *lpstrCurrFile++ = '\"';
3104 strcpy( lpstrCurrFile, lpstrTemp );
3105 lpstrCurrFile += strlen( lpstrTemp );
3106 strcpy( lpstrCurrFile, "\" " );
3107 lpstrCurrFile += 2;
3109 else
3111 strcpy( lpstrAllFile, lpstrTemp );
3114 COMDLG32_SHFree( (LPVOID) pidl );
3117 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3119 /* Select the file name like Windows does */
3120 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
3122 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3126 /* copied from shell32 to avoid linking to it
3127 * FIXME: why? shell32 is already linked
3129 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3131 switch (src->uType)
3133 case STRRET_WSTR:
3134 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
3135 COMDLG32_SHFree(src->u.pOleStr);
3136 break;
3138 case STRRET_CSTR:
3139 lstrcpynA((LPSTR)dest, src->u.cStr, len);
3140 break;
3142 case STRRET_OFFSET:
3143 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
3144 break;
3146 default:
3147 FIXME("unknown type!\n");
3148 if (len)
3150 *(LPSTR)dest = '\0';
3152 return(E_FAIL);
3154 return S_OK;
3157 /***********************************************************************
3158 * FILEDLG95_FILENAME_GetFileNames
3160 * Copies the filenames to a delimited string list.
3161 * The delimiter is specified by the parameter 'separator',
3162 * usually either a space or a nul
3164 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3166 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3167 UINT nStrCharCount = 0; /* index in src buffer */
3168 UINT nFileIndex = 0; /* index in dest buffer */
3169 UINT nFileCount = 0; /* number of files */
3170 UINT nStrLen = 0; /* length of string in edit control */
3171 LPWSTR lpstrEdit; /* buffer for string from edit control */
3173 TRACE("\n");
3175 /* get the filenames from the edit control */
3176 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3177 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3178 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3180 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3182 /* we might get single filename without any '"',
3183 * so we need nStrLen + terminating \0 + end-of-list \0 */
3184 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3185 *sizeUsed = 0;
3187 /* build delimited file list from filenames */
3188 while ( nStrCharCount <= nStrLen )
3190 if ( lpstrEdit[nStrCharCount]=='"' )
3192 nStrCharCount++;
3193 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3195 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3196 (*sizeUsed)++;
3197 nStrCharCount++;
3199 (*lpstrFileList)[nFileIndex++] = separator;
3200 (*sizeUsed)++;
3201 nFileCount++;
3203 nStrCharCount++;
3206 /* single, unquoted string */
3207 if ((nStrLen > 0) && (*sizeUsed == 0) )
3209 strcpyW(*lpstrFileList, lpstrEdit);
3210 nFileIndex = strlenW(lpstrEdit) + 1;
3211 (*sizeUsed) = nFileIndex;
3212 nFileCount = 1;
3215 /* trailing \0 */
3216 (*lpstrFileList)[nFileIndex] = '\0';
3217 (*sizeUsed)++;
3219 MemFree(lpstrEdit);
3220 return nFileCount;
3223 #define SETDefFormatEtc(fe,cf,med) \
3225 (fe).cfFormat = cf;\
3226 (fe).dwAspect = DVASPECT_CONTENT; \
3227 (fe).ptd =NULL;\
3228 (fe).tymed = med;\
3229 (fe).lindex = -1;\
3233 * DATAOBJECT Helper functions
3236 /***********************************************************************
3237 * COMCTL32_ReleaseStgMedium
3239 * like ReleaseStgMedium from ole32
3241 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3243 if(medium.pUnkForRelease)
3245 IUnknown_Release(medium.pUnkForRelease);
3247 else
3249 GlobalUnlock(medium.u.hGlobal);
3250 GlobalFree(medium.u.hGlobal);
3254 /***********************************************************************
3255 * GetPidlFromDataObject
3257 * Return pidl(s) by number from the cached DataObject
3259 * nPidlIndex=0 gets the fully qualified root path
3261 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3264 STGMEDIUM medium;
3265 FORMATETC formatetc;
3266 LPITEMIDLIST pidl = NULL;
3268 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3270 if (!doSelected)
3271 return NULL;
3273 /* Set the FORMATETC structure*/
3274 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3276 /* Get the pidls from IDataObject */
3277 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3279 LPIDA cida = GlobalLock(medium.u.hGlobal);
3280 if(nPidlIndex <= cida->cidl)
3282 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3284 COMCTL32_ReleaseStgMedium(medium);
3286 return pidl;
3289 /***********************************************************************
3290 * GetNumSelected
3292 * Return the number of selected items in the DataObject.
3295 UINT GetNumSelected( IDataObject *doSelected )
3297 UINT retVal = 0;
3298 STGMEDIUM medium;
3299 FORMATETC formatetc;
3301 TRACE("sv=%p\n", doSelected);
3303 if (!doSelected) return 0;
3305 /* Set the FORMATETC structure*/
3306 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3308 /* Get the pidls from IDataObject */
3309 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3311 LPIDA cida = GlobalLock(medium.u.hGlobal);
3312 retVal = cida->cidl;
3313 COMCTL32_ReleaseStgMedium(medium);
3314 return retVal;
3316 return 0;
3320 * TOOLS
3323 /***********************************************************************
3324 * GetName
3326 * Get the pidl's display name (relative to folder) and
3327 * put it in lpstrFileName.
3329 * Return NOERROR on success,
3330 * E_FAIL otherwise
3333 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3335 STRRET str;
3336 HRESULT hRes;
3338 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3340 if(!lpsf)
3342 SHGetDesktopFolder(&lpsf);
3343 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3344 IShellFolder_Release(lpsf);
3345 return hRes;
3348 /* Get the display name of the pidl relative to the folder */
3349 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3351 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3353 return E_FAIL;
3356 /***********************************************************************
3357 * GetShellFolderFromPidl
3359 * pidlRel is the item pidl relative
3360 * Return the IShellFolder of the absolute pidl
3362 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3364 IShellFolder *psf = NULL,*psfParent;
3366 TRACE("%p\n", pidlAbs);
3368 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3370 psf = psfParent;
3371 if(pidlAbs && pidlAbs->mkid.cb)
3373 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3375 IShellFolder_Release(psfParent);
3376 return psf;
3379 /* return the desktop */
3380 return psfParent;
3382 return NULL;
3385 /***********************************************************************
3386 * GetParentPidl
3388 * Return the LPITEMIDLIST to the parent of the pidl in the list
3390 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3392 LPITEMIDLIST pidlParent;
3394 TRACE("%p\n", pidl);
3396 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3397 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3399 return pidlParent;
3402 /***********************************************************************
3403 * GetPidlFromName
3405 * returns the pidl of the file name relative to folder
3406 * NULL if an error occurred
3408 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3410 LPITEMIDLIST pidl = NULL;
3411 ULONG ulEaten;
3413 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3415 if(!lpcstrFileName) return NULL;
3416 if(!*lpcstrFileName) return NULL;
3418 if(!lpsf)
3420 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3421 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3422 IShellFolder_Release(lpsf);
3425 else
3427 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3429 return pidl;
3434 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3436 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3437 HRESULT ret;
3439 TRACE("%p, %p\n", psf, pidl);
3441 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3443 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3444 /* see documentation shell 4.1*/
3445 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3448 /***********************************************************************
3449 * BrowseSelectedFolder
3451 static BOOL BrowseSelectedFolder(HWND hwnd)
3453 BOOL bBrowseSelFolder = FALSE;
3454 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3456 TRACE("\n");
3458 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3460 LPITEMIDLIST pidlSelection;
3462 /* get the file selected */
3463 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3464 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3466 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3467 pidlSelection, SBSP_RELATIVE ) ) )
3469 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3470 ' ','n','o','t',' ','e','x','i','s','t',0};
3471 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3473 bBrowseSelFolder = TRUE;
3474 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3476 COMDLG32_SHFree( pidlSelection );
3479 return bBrowseSelFolder;
3483 * Memory allocation methods */
3484 static void *MemAlloc(UINT size)
3486 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3489 static void MemFree(void *mem)
3491 HeapFree(GetProcessHeap(),0,mem);
3495 * Old-style (win3.1) dialogs */
3497 /***********************************************************************
3498 * FD32_GetTemplate [internal]
3500 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3501 * by a 32 bits application
3504 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3506 LPOPENFILENAMEW ofnW = lfs->ofnW;
3507 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3508 HANDLE hDlgTmpl;
3510 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3512 if (!(lfs->template = LockResource( ofnW->hInstance )))
3514 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3515 return FALSE;
3518 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3520 HRSRC hResInfo;
3521 if (priv->ofnA)
3522 hResInfo = FindResourceA(priv->ofnA->hInstance,
3523 priv->ofnA->lpTemplateName,
3524 (LPSTR)RT_DIALOG);
3525 else
3526 hResInfo = FindResourceW(ofnW->hInstance,
3527 ofnW->lpTemplateName,
3528 (LPWSTR)RT_DIALOG);
3529 if (!hResInfo)
3531 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3532 return FALSE;
3534 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3535 hResInfo)) ||
3536 !(lfs->template = LockResource(hDlgTmpl)))
3538 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3539 return FALSE;
3541 } else { /* get it from internal Wine resource */
3542 HRSRC hResInfo;
3543 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3544 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3546 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3547 return FALSE;
3549 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3550 !(lfs->template = LockResource( hDlgTmpl )))
3552 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3553 return FALSE;
3556 return TRUE;
3560 /************************************************************************
3561 * FD32_Init [internal]
3562 * called from the common 16/32 code to initialize 32 bit data
3564 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3566 BOOL IsUnicode = (BOOL) data;
3567 PFD32_PRIVATE priv;
3569 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3570 lfs->private1632 = priv;
3571 if (NULL == lfs->private1632) return FALSE;
3572 if (IsUnicode)
3574 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3575 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3576 if (lfs->ofnW->lpfnHook)
3577 lfs->hook = TRUE;
3579 else
3581 priv->ofnA = (LPOPENFILENAMEA) lParam;
3582 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3583 if (priv->ofnA->lpfnHook)
3584 lfs->hook = TRUE;
3585 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3586 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3589 if (! FD32_GetTemplate(lfs)) return FALSE;
3591 return TRUE;
3594 /***********************************************************************
3595 * FD32_CallWindowProc [internal]
3597 * called from the common 16/32 code to call the appropriate hook
3599 static BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
3600 LPARAM lParam)
3602 BOOL ret;
3603 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3605 if (priv->ofnA)
3607 TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3608 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3609 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3610 TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3611 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3612 return ret;
3615 TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3616 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3617 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3618 TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3619 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3620 return ret;
3623 /***********************************************************************
3624 * FD32_UpdateResult [internal]
3625 * update the real client structures if any
3627 static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs)
3629 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3630 LPOPENFILENAMEW ofnW = lfs->ofnW;
3632 if (priv->ofnA)
3634 if (ofnW->nMaxFile &&
3635 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3636 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3637 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3638 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3639 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3643 /***********************************************************************
3644 * FD32_UpdateFileTitle [internal]
3645 * update the real client structures if any
3647 static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs)
3649 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3650 LPOPENFILENAMEW ofnW = lfs->ofnW;
3652 if (priv->ofnA)
3654 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3655 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3656 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3661 /***********************************************************************
3662 * FD32_SendLbGetCurSel [internal]
3663 * retrieve selected listbox item
3665 static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs)
3667 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3671 /************************************************************************
3672 * FD32_Destroy [internal]
3673 * called from the common 16/32 code to cleanup 32 bit data
3675 static void CALLBACK FD32_Destroy(PFD31_DATA lfs)
3677 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3679 /* if ofnW has been allocated, have to free everything in it */
3680 if (NULL != priv && NULL != priv->ofnA)
3682 FD31_FreeOfnW(lfs->ofnW);
3683 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3687 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3689 callbacks->Init = FD32_Init;
3690 callbacks->CWP = FD32_CallWindowProc;
3691 callbacks->UpdateResult = FD32_UpdateResult;
3692 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3693 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3694 callbacks->Destroy = FD32_Destroy;
3697 /***********************************************************************
3698 * FD32_WMMeasureItem [internal]
3700 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3702 LPMEASUREITEMSTRUCT lpmeasure;
3704 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3705 lpmeasure->itemHeight = FD31_GetFldrHeight();
3706 return TRUE;
3710 /***********************************************************************
3711 * FileOpenDlgProc [internal]
3712 * Used for open and save, in fact.
3714 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3715 WPARAM wParam, LPARAM lParam)
3717 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3719 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
3720 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3722 INT_PTR lRet;
3723 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3724 if (lRet)
3725 return lRet; /* else continue message processing */
3727 switch (wMsg)
3729 case WM_INITDIALOG:
3730 return FD31_WMInitDialog(hWnd, wParam, lParam);
3732 case WM_MEASUREITEM:
3733 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3735 case WM_DRAWITEM:
3736 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3738 case WM_COMMAND:
3739 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3740 #if 0
3741 case WM_CTLCOLOR:
3742 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3743 switch (HIWORD(lParam))
3745 case CTLCOLOR_BTN:
3746 SetTextColor((HDC16)wParam, 0x00000000);
3747 return hGRAYBrush;
3748 case CTLCOLOR_STATIC:
3749 SetTextColor((HDC16)wParam, 0x00000000);
3750 return hGRAYBrush;
3752 break;
3753 #endif
3755 return FALSE;
3759 /***********************************************************************
3760 * GetFileName31A [internal]
3762 * Creates a win31 style dialog box for the user to select a file to open/save.
3764 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3765 UINT dlgType /* type dialogue : open/save */
3768 HINSTANCE hInst;
3769 BOOL bRet = FALSE;
3770 PFD31_DATA lfs;
3771 FD31_CALLBACKS callbacks;
3773 if (!lpofn || !FD31_Init()) return FALSE;
3775 TRACE("ofn flags %08lx\n", lpofn->Flags);
3776 FD32_SetupCallbacks(&callbacks);
3777 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3778 if (lfs)
3780 hInst = (HINSTANCE)GetWindowLongPtrA( lpofn->hwndOwner, GWLP_HINSTANCE );
3781 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3782 FD32_FileOpenDlgProc, (LPARAM)lfs);
3783 FD31_DestroyPrivate(lfs);
3786 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3787 return bRet;
3790 /***********************************************************************
3791 * GetFileName31W [internal]
3793 * Creates a win31 style dialog box for the user to select a file to open/save
3795 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3796 UINT dlgType /* type dialogue : open/save */
3799 HINSTANCE hInst;
3800 BOOL bRet = FALSE;
3801 PFD31_DATA lfs;
3802 FD31_CALLBACKS callbacks;
3804 if (!lpofn || !FD31_Init()) return FALSE;
3806 FD32_SetupCallbacks(&callbacks);
3807 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3808 if (lfs)
3810 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3811 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3812 FD32_FileOpenDlgProc, (LPARAM)lfs);
3813 FD31_DestroyPrivate(lfs);
3816 TRACE("file %s, file offset %d, ext offset %d\n",
3817 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3818 return bRet;
3821 /* ------------------ APIs ---------------------- */
3823 /***********************************************************************
3824 * GetOpenFileNameA (COMDLG32.@)
3826 * Creates a dialog box for the user to select a file to open.
3828 * RETURNS
3829 * TRUE on success: user enters a valid file
3830 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3833 BOOL WINAPI GetOpenFileNameA(
3834 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3836 BOOL win16look = FALSE;
3838 TRACE("flags %08lx\n", ofn->Flags);
3840 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3841 if (ofn->Flags & OFN_FILEMUSTEXIST)
3842 ofn->Flags |= OFN_PATHMUSTEXIST;
3844 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3845 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3847 if (win16look)
3848 return GetFileName31A(ofn, OPEN_DIALOG);
3849 else
3850 return GetFileDialog95A(ofn, OPEN_DIALOG);
3853 /***********************************************************************
3854 * GetOpenFileNameW (COMDLG32.@)
3856 * Creates a dialog box for the user to select a file to open.
3858 * RETURNS
3859 * TRUE on success: user enters a valid file
3860 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3863 BOOL WINAPI GetOpenFileNameW(
3864 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3866 BOOL win16look = FALSE;
3868 TRACE("flags %08lx\n", ofn->Flags);
3870 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3871 if (ofn->Flags & OFN_FILEMUSTEXIST)
3872 ofn->Flags |= OFN_PATHMUSTEXIST;
3874 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3875 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3877 if (win16look)
3878 return GetFileName31W(ofn, OPEN_DIALOG);
3879 else
3880 return GetFileDialog95W(ofn, OPEN_DIALOG);
3884 /***********************************************************************
3885 * GetSaveFileNameA (COMDLG32.@)
3887 * Creates a dialog box for the user to select a file to save.
3889 * RETURNS
3890 * TRUE on success: user enters a valid file
3891 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3894 BOOL WINAPI GetSaveFileNameA(
3895 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3897 BOOL win16look = FALSE;
3899 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3900 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3902 if (win16look)
3903 return GetFileName31A(ofn, SAVE_DIALOG);
3904 else
3905 return GetFileDialog95A(ofn, SAVE_DIALOG);
3908 /***********************************************************************
3909 * GetSaveFileNameW (COMDLG32.@)
3911 * Creates a dialog box for the user to select a file to save.
3913 * RETURNS
3914 * TRUE on success: user enters a valid file
3915 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3918 BOOL WINAPI GetSaveFileNameW(
3919 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3921 BOOL win16look = FALSE;
3923 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3924 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3926 if (win16look)
3927 return GetFileName31W(ofn, SAVE_DIALOG);
3928 else
3929 return GetFileDialog95W(ofn, SAVE_DIALOG);