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 expecting 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 if would likely cause
26 * a complete rewrite with after we shouldhandle 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: lpstrCustomFilter not handled
37 * FIXME: if the size of lpstrFile (nMaxFile) is too small the first
38 * two bytes of lpstrFile should contain the needed size
40 * FIXME: algorithm for selecting the initial directory is too simple
42 * FIXME: add to recent docs
44 * FIXME: flags not implemented: OFN_CREATEPROMPT, OFN_DONTADDTORECENT,
45 * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING, OFN_EXTENSIONDIFFERENT,
46 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
47 * OFN_NOTESTFILECREATE, OFN_OVERWRITEPROMPT, OFN_USEMONIKERS
49 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
55 #include "wine/port.h"
65 #include "wine/unicode.h"
69 #include "wine/debug.h"
73 #include "filedlgbrowser.h"
75 #include "wine/obj_contextmenu.h"
77 WINE_DEFAULT_DEBUG_CHANNEL(commdlg
);
79 #define UNIMPLEMENTED_FLAGS \
80 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
81 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING | OFN_EXTENSIONDIFFERENT |\
82 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
83 OFN_NOTESTFILECREATE | OFN_OVERWRITEPROMPT /*| OFN_USEMONIKERS*/)
85 #define IsHooked(fodInfos) \
86 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
87 /***********************************************************************
88 * Data structure and global variables
90 typedef struct SFolder
92 int m_iImageIndex
; /* Index of picture in image list */
94 int m_iIndent
; /* Indentation index */
95 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
99 typedef struct tagLookInInfo
106 /***********************************************************************
107 * Defines and global variables
110 /* Draw item constant */
112 #define XTEXTOFFSET 3
117 /* SearchItem methods */
118 #define SEARCH_PIDL 1
120 #define ITEM_NOTFOUND -1
122 /* Undefined windows message sent by CreateViewObject*/
123 #define WM_GETISHELLBROWSER WM_USER+7
126 * Those macros exist in windowsx.h. However, you can't really use them since
127 * they rely on the UNICODE defines and can't be used inside Wine itself.
130 /* Combo box macros */
131 #define CBAddString(hwnd,str) \
132 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
133 #define CBAddStringW(hwnd,str) \
134 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
136 #define CBInsertString(hwnd,str,pos) \
137 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
139 #define CBDeleteString(hwnd,pos) \
140 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
142 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
143 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
145 #define CBGetItemDataPtr(hwnd,iItemId) \
146 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
148 #define CBGetLBText(hwnd,iItemId,str) \
149 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
151 #define CBGetCurSel(hwnd) \
152 SendMessageA(hwnd,CB_GETCURSEL,0,0);
154 #define CBSetCurSel(hwnd,pos) \
155 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
157 #define CBGetCount(hwnd) \
158 SendMessageA(hwnd,CB_GETCOUNT,0,0);
159 #define CBShowDropDown(hwnd,show) \
160 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
161 #define CBSetItemHeight(hwnd,index,height) \
162 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
165 const char *FileOpenDlgInfosStr
= "FileOpenDlgInfos"; /* windows property description string */
166 const char *LookInInfosStr
= "LookInInfos"; /* LOOKIN combo box property */
168 /***********************************************************************
172 /* Internal functions used by the dialog */
173 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
174 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
175 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
176 BOOL
FILEDLG95_OnOpen(HWND hwnd
);
177 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
178 static void FILEDLG95_Clean(HWND hwnd
);
180 /* Functions used by the shell navigation */
181 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
182 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
183 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
184 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
185 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
);
187 /* Functions used by the filetype combo box */
188 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
189 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
190 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
191 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
193 /* Functions used by the Look In combo box */
194 static HRESULT
FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
195 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
196 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
197 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
198 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
199 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
200 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
201 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
202 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
204 /* Miscellaneous tool functions */
205 HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPSTR lpstrFileName
);
206 HRESULT
GetFileName(HWND hwnd
, LPITEMIDLIST pidl
, LPSTR lpstrFileName
);
207 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
208 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
209 LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
211 /* Shell memory allocation */
212 static void *MemAlloc(UINT size
);
213 static void MemFree(void *mem
);
215 BOOL WINAPI
GetFileName95(FileOpenDlgInfos
*fodInfos
);
216 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
217 HRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
);
218 HRESULT
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
219 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
220 static BOOL
BrowseSelectedFolder(HWND hwnd
);
222 LPWSTR
strpbrkW(LPWSTR str
, LPCWSTR clist
)
228 for(p
= clist
; *p
; p
++ )
236 /***********************************************************************
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 BOOL WINAPI
GetFileName95(FileOpenDlgInfos
*fodInfos
)
254 /* test for missing functionality */
255 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
257 FIXME("Flags 0x%08lx not yet implemented\n",
258 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
261 /* Create the dialog from a template */
263 if(!(hRes
= FindResourceA(COMMDLG_hInstance32
,MAKEINTRESOURCEA(NEWFILEOPENORD
),RT_DIALOGA
)))
265 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
268 if (!(hDlgTmpl
= LoadResource(COMMDLG_hInstance32
, hRes
)) ||
269 !(template = LockResource( hDlgTmpl
)))
271 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
275 /* old style hook messages */
276 if (IsHooked(fodInfos
))
278 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageA(FILEOKSTRINGA
);
279 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageA(LBSELCHSTRINGA
);
280 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageA(HELPMSGSTRINGA
);
281 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageA(SHAREVISTRINGA
);
284 lRes
= DialogBoxIndirectParamA(COMMDLG_hInstance32
,
285 (LPDLGTEMPLATEA
) template,
286 fodInfos
->ofnInfos
->hwndOwner
,
290 /* Unable to create the dialog */
297 /***********************************************************************
300 * Call GetFileName95 with this structure and clean the memory.
302 * IN : The OPENFILENAMEA initialisation structure passed to
303 * GetOpenFileNameA win api function (see filedlg.c)
305 BOOL WINAPI
GetFileDialog95A(LPOPENFILENAMEA ofn
,UINT iDlgType
)
308 FileOpenDlgInfos fodInfos
;
309 LPSTR lpstrSavDir
= NULL
;
311 LPWSTR defext
= NULL
;
312 LPWSTR filter
= NULL
;
313 LPWSTR customfilter
= NULL
;
315 /* Initialize FileOpenDlgInfos structure */
316 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
318 /* Pass in the original ofn */
319 fodInfos
.ofnInfos
= ofn
;
321 /* save current directory */
322 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
324 lpstrSavDir
= MemAlloc(MAX_PATH
);
325 GetCurrentDirectoryA(MAX_PATH
, lpstrSavDir
);
328 fodInfos
.unicode
= FALSE
;
330 /* convert all the input strings to unicode */
331 if(ofn
->lpstrInitialDir
)
333 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, NULL
, 0 );
334 fodInfos
.initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
335 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, fodInfos
.initdir
, len
);
338 fodInfos
.initdir
= NULL
;
342 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
343 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFile
, -1, fodInfos
.filename
, ofn
->nMaxFile
);
346 fodInfos
.filename
= NULL
;
350 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, NULL
, 0 );
351 defext
= MemAlloc((len
+1)*sizeof(WCHAR
));
352 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, defext
, len
);
354 fodInfos
.defext
= defext
;
358 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, NULL
, 0 );
359 title
= MemAlloc((len
+1)*sizeof(WCHAR
));
360 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, title
, len
);
362 fodInfos
.title
= title
;
364 if (ofn
->lpstrFilter
)
369 /* filter is a list... title\0ext\0......\0\0 */
370 s
= ofn
->lpstrFilter
;
371 while (*s
) s
= s
+strlen(s
)+1;
373 n
= s
- ofn
->lpstrFilter
;
374 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0 );
375 filter
= MemAlloc(len
*sizeof(WCHAR
));
376 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, filter
, len
);
378 fodInfos
.filter
= filter
;
380 /* convert lpstrCustomFilter */
381 if (ofn
->lpstrCustomFilter
)
386 /* filter is a list... title\0ext\0......\0\0 */
387 s
= ofn
->lpstrCustomFilter
;
388 while (*s
) s
= s
+strlen(s
)+1;
390 n
= s
- ofn
->lpstrCustomFilter
;
391 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0 );
392 customfilter
= MemAlloc(len
*sizeof(WCHAR
));
393 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, customfilter
, len
);
395 fodInfos
.customfilter
= customfilter
;
397 /* Initialize the dialog property */
398 fodInfos
.DlgInfos
.dwDlgProp
= 0;
399 fodInfos
.DlgInfos
.hwndCustomDlg
= (HWND
)NULL
;
404 ret
= GetFileName95(&fodInfos
);
407 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
408 ret
= GetFileName95(&fodInfos
);
416 SetCurrentDirectoryA(lpstrSavDir
);
417 MemFree(lpstrSavDir
);
427 MemFree(customfilter
);
429 MemFree(fodInfos
.initdir
);
431 if(fodInfos
.filename
)
432 MemFree(fodInfos
.filename
);
434 TRACE("selected file: %s\n",ofn
->lpstrFile
);
439 /***********************************************************************
442 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
443 * Call GetFileName95 with this structure and clean the memory.
445 * FIXME: lpstrCustomFilter has to be converted back
448 BOOL WINAPI
GetFileDialog95W(LPOPENFILENAMEW ofn
,UINT iDlgType
)
451 FileOpenDlgInfos fodInfos
;
452 LPSTR lpstrSavDir
= NULL
;
454 /* Initialize FileOpenDlgInfos structure */
455 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
457 /* Pass in the original ofn */
458 fodInfos
.ofnInfos
= (LPOPENFILENAMEA
) ofn
;
460 fodInfos
.title
= ofn
->lpstrTitle
;
461 fodInfos
.defext
= ofn
->lpstrDefExt
;
462 fodInfos
.filter
= ofn
->lpstrFilter
;
463 fodInfos
.customfilter
= ofn
->lpstrCustomFilter
;
465 /* convert string arguments, save others */
468 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
469 strncpyW(fodInfos
.filename
,ofn
->lpstrFile
,ofn
->nMaxFile
);
472 fodInfos
.filename
= NULL
;
474 if(ofn
->lpstrInitialDir
)
476 DWORD len
= strlenW(ofn
->lpstrInitialDir
);
477 fodInfos
.initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
478 strcpyW(fodInfos
.initdir
,ofn
->lpstrInitialDir
);
481 fodInfos
.initdir
= NULL
;
483 /* save current directory */
484 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
486 lpstrSavDir
= MemAlloc(MAX_PATH
);
487 GetCurrentDirectoryA(MAX_PATH
, lpstrSavDir
);
490 fodInfos
.unicode
= TRUE
;
495 ret
= GetFileName95(&fodInfos
);
498 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
499 ret
= GetFileName95(&fodInfos
);
507 SetCurrentDirectoryA(lpstrSavDir
);
508 MemFree(lpstrSavDir
);
511 /* restore saved IN arguments and convert OUT arguments back */
512 MemFree(fodInfos
.filename
);
513 MemFree(fodInfos
.initdir
);
517 void ArrangeCtrlPositions( HWND hwndChildDlg
, HWND hwndParentDlg
)
519 HWND hwndChild
,hwndStc32
;
520 RECT rectParent
, rectChild
, rectCtrl
, rectStc32
, rectTemp
;
522 POINT ptParentClient
;
526 ptMoveCtl
.x
= ptMoveCtl
.y
= 0;
527 hwndStc32
=GetDlgItem(hwndChildDlg
,stc32
);
528 GetClientRect(hwndParentDlg
,&rectParent
);
529 GetClientRect(hwndChildDlg
,&rectChild
);
533 GetWindowRect(hwndStc32
,&rectStc32
);
534 MapWindowPoints(0, hwndChildDlg
,(LPPOINT
)&rectStc32
,2);
535 CopyRect(&rectTemp
,&rectStc32
);
537 SetRect(&rectStc32
,rectStc32
.left
,rectStc32
.top
,rectStc32
.left
+ (rectParent
.right
-rectParent
.left
),rectStc32
.top
+(rectParent
.bottom
-rectParent
.top
));
538 SetWindowPos(hwndStc32
,0,rectStc32
.left
,rectStc32
.top
,rectStc32
.right
-rectStc32
.left
,rectStc32
.bottom
-rectStc32
.top
,SWP_NOMOVE
|SWP_NOZORDER
| SWP_NOACTIVATE
);
540 ptParentClient
.x
= max((rectParent
.right
-rectParent
.left
),(rectChild
.right
-rectChild
.left
));
541 if(rectStc32
.right
< rectTemp
.right
)
544 ptMoveCtl
.x
= (rectStc32
.right
- rectTemp
.right
);
546 ptParentClient
.y
= max((rectParent
.bottom
-rectParent
.top
),(rectChild
.bottom
-rectChild
.top
));
547 if(rectStc32
.bottom
< rectTemp
.bottom
)
550 ptMoveCtl
.y
= (rectStc32
.bottom
- rectTemp
.bottom
);
554 if( (GetWindow(hwndChildDlg
,GW_CHILD
)) == (HWND
) NULL
) return;
556 SetRectEmpty(&rectTemp
);
557 ptParentClient
.x
= max((rectParent
.right
-rectParent
.left
),(rectChild
.right
-rectChild
.left
));
558 ptParentClient
.y
= (rectParent
.bottom
-rectParent
.top
) + (rectChild
.bottom
-rectChild
.top
);
559 ptMoveCtl
.y
= rectParent
.bottom
-rectParent
.top
;
562 SetRect(&rectParent
,rectParent
.left
,rectParent
.top
,rectParent
.left
+ptParentClient
.x
,rectParent
.top
+ptParentClient
.y
);
563 AdjustWindowRectEx( &rectParent
,GetWindowLongA(hwndParentDlg
,GWL_STYLE
),FALSE
,GetWindowLongA(hwndParentDlg
,GWL_EXSTYLE
));
565 SetWindowPos(hwndChildDlg
, 0, 0,0, ptParentClient
.x
,ptParentClient
.y
, SWP_NOZORDER
);
566 SetWindowPos(hwndParentDlg
, 0, rectParent
.left
,rectParent
.top
, (rectParent
.right
- rectParent
.left
),
567 (rectParent
.bottom
-rectParent
.top
),SWP_NOMOVE
| SWP_NOZORDER
);
569 hwndChild
= GetWindow(hwndChildDlg
,GW_CHILD
);
572 GetWindowRect(hwndStc32
,&rectStc32
);
573 MapWindowPoints( 0, hwndChildDlg
,(LPPOINT
)&rectStc32
,2);
576 SetRect(&rectStc32
,0,0,0,0);
582 if(hwndChild
!= hwndStc32
)
584 if (GetWindowLongA( hwndChild
, GWL_STYLE
) & WS_MAXIMIZE
)
586 GetWindowRect(hwndChild
,&rectCtrl
);
587 MapWindowPoints( 0, hwndParentDlg
,(LPPOINT
)&rectCtrl
,2);
590 Check the initial position of the controls relative to the initial
591 position and size of stc32 (before it is expanded).
593 if (rectCtrl
.left
>= rectTemp
.right
&& rectCtrl
.top
>= rectTemp
.bottom
)
595 rectCtrl
.left
+= ptMoveCtl
.x
;
596 rectCtrl
.top
+= ptMoveCtl
.y
;
598 else if (rectCtrl
.left
>= rectTemp
.right
)
600 rectCtrl
.left
+= ptMoveCtl
.x
;
602 else if (rectCtrl
.top
>= rectTemp
.bottom
)
604 rectCtrl
.top
+= ptMoveCtl
.y
;
607 SetWindowPos( hwndChild
, 0, rectCtrl
.left
, rectCtrl
.top
,
608 rectCtrl
.right
-rectCtrl
.left
,rectCtrl
.bottom
-rectCtrl
.top
,
609 SWP_NOSIZE
| SWP_NOZORDER
);
611 } while ((hwndChild
=GetWindow( hwndChild
, GW_HWNDNEXT
)) != (HWND
)NULL
);
613 hwndChild
= GetWindow(hwndParentDlg
,GW_CHILD
);
617 GetWindowRect(hwndStc32
,&rectStc32
);
618 MapWindowPoints( 0, hwndChildDlg
,(LPPOINT
)&rectStc32
,2);
619 ptMoveCtl
.x
= rectStc32
.left
- 0;
620 ptMoveCtl
.y
= rectStc32
.top
- 0;
625 if(hwndChild
!= hwndChildDlg
)
627 if (GetWindowLongA( hwndChild
, GWL_STYLE
) & WS_MAXIMIZE
)
629 GetWindowRect(hwndChild
,&rectCtrl
);
630 MapWindowPoints( 0, hwndParentDlg
,(LPPOINT
)&rectCtrl
,2);
632 rectCtrl
.left
+= ptMoveCtl
.x
;
633 rectCtrl
.top
+= ptMoveCtl
.y
;
635 SetWindowPos( hwndChild
, 0, rectCtrl
.left
, rectCtrl
.top
,
636 rectCtrl
.right
-rectCtrl
.left
,rectCtrl
.bottom
-rectCtrl
.top
,
637 SWP_NOSIZE
|SWP_NOZORDER
);
639 } while ((hwndChild
=GetWindow( hwndChild
, GW_HWNDNEXT
)) != (HWND
)NULL
);
645 INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
647 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(GetParent(hwnd
),FileOpenDlgInfosStr
);
650 TRACE("0x%04x\n", uMsg
);
657 /* Hide caption since some program may leave it */
658 DWORD Style
= GetWindowLongA(hwnd
, GWL_STYLE
);
659 if (Style
& WS_CAPTION
) SetWindowLongA(hwnd
, GWL_STYLE
, Style
& (~WS_CAPTION
));
661 fodInfos
= (FileOpenDlgInfos
*)lParam
;
662 lParam
= (LPARAM
) fodInfos
->ofnInfos
;
663 ArrangeCtrlPositions(hwnd
,GetParent(hwnd
));
665 if(fodInfos
&& IsHooked(fodInfos
))
666 return CallWindowProcA((WNDPROC
)fodInfos
->ofnInfos
->lpfnHook
,hwnd
,uMsg
,wParam
,lParam
);
671 if(fodInfos
&& IsHooked(fodInfos
))
672 return CallWindowProcA((WNDPROC
)fodInfos
->ofnInfos
->lpfnHook
,hwnd
,uMsg
,wParam
,lParam
);
674 return DefWindowProcA(hwnd
,uMsg
,wParam
,lParam
);
677 HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
687 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
688 * structure's hInstance parameter is not a HINSTANCE, but
689 * instead a pointer to a template resource to use.
691 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATE
||
692 fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
696 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
699 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
701 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
707 hinst
= fodInfos
->ofnInfos
->hInstance
;
708 if(fodInfos
->unicode
)
710 LPOPENFILENAMEW ofn
= (LPOPENFILENAMEW
) fodInfos
->ofnInfos
;
711 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, RT_DIALOGW
);
715 LPOPENFILENAMEA ofn
= fodInfos
->ofnInfos
;
716 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, RT_DIALOGA
);
720 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
723 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
724 !(template = LockResource( hDlgTmpl
)))
726 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
731 hChildDlg
= CreateDialogIndirectParamA(hinst
, template,
732 hwnd
, FileOpenDlgProcUserTemplate
, (LPARAM
)fodInfos
);
735 ShowWindow(hChildDlg
,SW_SHOW
);
739 else if( IsHooked(fodInfos
))
744 WORD menu
,class,title
;
746 GetClientRect(hwnd
,&rectHwnd
);
747 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
;
748 temp
.tmplate
.dwExtendedStyle
= 0;
749 temp
.tmplate
.cdit
= 0;
752 temp
.tmplate
.cx
= rectHwnd
.right
-rectHwnd
.left
;
753 temp
.tmplate
.cy
= rectHwnd
.bottom
-rectHwnd
.top
;
754 temp
.menu
= temp
.class = temp
.title
= 0;
755 hChildDlg
= CreateDialogIndirectParamA(fodInfos
->ofnInfos
->hInstance
,&temp
.tmplate
,
756 hwnd
, FileOpenDlgProcUserTemplate
, (LPARAM
)fodInfos
);
762 /***********************************************************************
763 * SendCustomDlgNotificationMessage
765 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
768 HRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
770 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwndParentDlg
,FileOpenDlgInfosStr
);
772 TRACE("0x%04x 0x%04x\n",hwndParentDlg
, uCode
);
774 if(!fodInfos
) return 0;
776 if(fodInfos
->unicode
)
777 FIXME("sending OPENFILENAMEA structure. Hook is expecting OPENFILENAMEW!\n");
779 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
783 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
784 ofnNotify
.hdr
.idFrom
=0;
785 ofnNotify
.hdr
.code
= uCode
;
786 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
787 TRACE("CALL NOTIFY for %x\n", uCode
);
788 ret
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
789 TRACE("RET NOTIFY\n");
795 HRESULT
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPSTR buffer
)
797 UINT sizeUsed
= 0, n
, total
;
798 LPWSTR lpstrFileList
= NULL
;
799 WCHAR lpstrCurrentDir
[MAX_PATH
];
800 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
802 TRACE("CDM_GETFILEPATH:\n");
804 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
807 /* get path and filenames */
808 SHGetPathFromIDListW(fodInfos
->ShellInfos
.pidlAbsCurrent
,lpstrCurrentDir
);
809 n
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
811 TRACE("path >%s< filespec >%s< %d files\n",
812 debugstr_w(lpstrCurrentDir
),debugstr_w(lpstrFileList
),n
);
814 total
= WideCharToMultiByte(CP_ACP
, 0, lpstrCurrentDir
, -1,
815 NULL
, 0, NULL
, NULL
);
816 total
+= WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
817 NULL
, 0, NULL
, NULL
);
819 /* Prepend the current path */
820 n
= WideCharToMultiByte(CP_ACP
, 0, lpstrCurrentDir
, -1,
821 buffer
, size
, NULL
, NULL
);
824 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
825 &buffer
[n
], size
-n
, NULL
, NULL
);
826 MemFree(lpstrFileList
);
828 TRACE("returned -> %s\n",debugstr_a(buffer
));
833 HRESULT
FILEDLG95_Handle_GetFileSpec(HWND hwnd
, DWORD size
, LPSTR buffer
)
836 LPWSTR lpstrFileList
= NULL
;
838 TRACE("CDM_GETSPEC:\n");
840 FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
841 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
, buffer
, size
, NULL
, NULL
);
842 MemFree(lpstrFileList
);
847 /***********************************************************************
848 * FILEDLG95_HandleCustomDialogMessages
850 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
852 HRESULT
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
854 char lpstrPath
[MAX_PATH
];
855 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
856 if(!fodInfos
) return -1;
860 case CDM_GETFILEPATH
:
861 return FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPSTR
)lParam
);
863 case CDM_GETFOLDERPATH
:
864 TRACE("CDM_GETFOLDERPATH:\n");
865 SHGetPathFromIDListA(fodInfos
->ShellInfos
.pidlAbsCurrent
,lpstrPath
);
866 if ((LPSTR
)lParam
!=NULL
)
867 lstrcpynA((LPSTR
)lParam
,lpstrPath
,(int)wParam
);
868 return strlen(lpstrPath
);
871 return FILEDLG95_Handle_GetFileSpec(hwnd
, (UINT
)wParam
, (LPSTR
)lParam
);
873 case CDM_SETCONTROLTEXT
:
874 TRACE("CDM_SETCONTROLTEXT:\n");
876 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
879 case CDM_HIDECONTROL
:
881 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
887 /***********************************************************************
890 * File open dialog procedure
892 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
895 TRACE("0x%04x 0x%04x\n", hwnd
, uMsg
);
902 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
904 /* Adds the FileOpenDlgInfos in the property list of the dialog
905 so it will be easily accessible through a GetPropA(...) */
906 SetPropA(hwnd
, FileOpenDlgInfosStr
, (HANDLE
) fodInfos
);
908 fodInfos
->DlgInfos
.hwndCustomDlg
=
909 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
911 FILEDLG95_InitControls(hwnd
);
912 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
913 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
914 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
915 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
916 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
917 0,0,0,0, SWP_NOMOVE
|SWP_NOSIZE
);
921 return FILEDLG95_OnWMCommand(hwnd
, wParam
, lParam
);
924 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
927 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
933 case WM_GETISHELLBROWSER
:
934 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
937 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
942 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
945 /* set up the button tooltips strings */
946 if(TTN_GETDISPINFOA
== lpnmh
->code
)
948 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
949 switch(lpnmh
->idFrom
)
951 /* Up folder button */
952 case FCIDM_TB_UPFOLDER
:
953 stringId
= IDS_UPFOLDER
;
955 /* New folder button */
956 case FCIDM_TB_NEWFOLDER
:
957 stringId
= IDS_NEWFOLDER
;
959 /* List option button */
960 case FCIDM_TB_SMALLICON
:
961 stringId
= IDS_LISTVIEW
;
963 /* Details option button */
964 case FCIDM_TB_REPORTVIEW
:
965 stringId
= IDS_REPORTVIEW
;
968 case FCIDM_TB_DESKTOP
:
969 stringId
= IDS_TODESKTOP
;
974 lpdi
->hinst
= COMMDLG_hInstance32
;
975 lpdi
->lpszText
= (LPSTR
) stringId
;
980 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
981 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
986 /***********************************************************************
987 * FILEDLG95_InitControls
989 * WM_INITDIALOG message handler (before hook notification)
991 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
995 int handledPath
= FALSE
;
997 const WCHAR szwSlash
[] = { '\\', 0 };
998 const WCHAR szwStar
[] = { '*',0 };
1002 {0, 0, TBSTATE_ENABLED
, TBSTYLE_SEP
, {0, 0}, 0, 0 },
1003 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, TBSTYLE_BUTTON
, {0, 0}, 0, 0 },
1004 {0, 0, TBSTATE_ENABLED
, TBSTYLE_SEP
, {0, 0}, 0, 0 },
1005 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, TBSTYLE_BUTTON
, {0, 0}, 0, 0 },
1006 {0, 0, TBSTATE_ENABLED
, TBSTYLE_SEP
, {0, 0}, 0, 0 },
1007 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, TBSTYLE_BUTTON
, {0, 0}, 0, 0 },
1008 {0, 0, TBSTATE_ENABLED
, TBSTYLE_SEP
, {0, 0}, 0, 0 },
1009 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, TBSTYLE_BUTTON
, {0, 0}, 0, 0 },
1010 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, TBSTYLE_BUTTON
, {0, 0}, 0, 0 },
1014 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1016 tba
[0].hInst
= HINST_COMMCTRL
;
1017 tba
[0].nID
= IDB_VIEW_SMALL_COLOR
;
1018 tba
[1].hInst
= COMDLG32_hInstance
;
1021 TRACE("%p\n", fodInfos
);
1023 /* Get windows version emulating */
1024 osVi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
1025 GetVersionExA(&osVi
);
1026 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1027 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1028 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1029 win2000plus
= (osVi
.dwMajorVersion
> 4);
1030 if (win2000plus
) win98plus
= TRUE
;
1032 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1034 /* Get the hwnd of the controls */
1035 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem(hwnd
,IDC_FILENAME
);
1036 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1037 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1039 /* construct the toolbar */
1040 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1041 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1043 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, (LPSTR
) NULL
,
1044 WS_CHILD
| WS_GROUP
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1045 0, 0, 150, 26, hwnd
, (HMENU
) IDC_TOOLBAR
, COMMDLG_hInstance32
, NULL
);
1047 SetWindowPos(fodInfos
->DlgInfos
.hwndTB
, 0,
1048 rectTB
.left
,rectTB
.top
, rectTB
.right
-rectTB
.left
, rectTB
.bottom
-rectTB
.top
,
1049 SWP_SHOWWINDOW
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1051 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, (WPARAM
) sizeof(TBBUTTON
), 0);
1053 /* FIXME: use TB_LOADIMAGES when implemented */
1054 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1055 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, (WPARAM
) 12, (LPARAM
) &tba
[0]);
1056 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, (WPARAM
) 1, (LPARAM
) &tba
[1]);
1058 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSA
, (WPARAM
) 9,(LPARAM
) &tbb
);
1059 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1061 /* Set the window text with the text specified in the OPENFILENAME structure */
1064 SetWindowTextW(hwnd
,fodInfos
->title
);
1066 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1068 SetWindowTextA(hwnd
,"Save");
1071 /* Initialise the file name edit control */
1072 handledPath
= FALSE
;
1073 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1075 if(fodInfos
->filename
)
1077 /* 1. If win2000 or higher and filename contains a path, use it
1078 in preference over the lpstrInitialDir */
1079 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1080 WCHAR tmpBuf
[MAX_PATH
];
1084 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1087 /* nameBit is always shorter than the original filename */
1088 strcpyW(fodInfos
->filename
,nameBit
);
1091 if (fodInfos
->initdir
== NULL
)
1092 MemFree(fodInfos
->initdir
);
1093 fodInfos
->initdir
= MemAlloc((strlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1094 strcpyW(fodInfos
->initdir
, tmpBuf
);
1096 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1097 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1099 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1102 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1106 /* 2. (All platforms) If initdir is not null, then use it */
1107 if ((handledPath
== FALSE
) && (fodInfos
->initdir
!=NULL
) &&
1108 (*fodInfos
->initdir
!=0x00))
1110 /* Work out the proper path as supplied one might be relative */
1111 /* (Here because supplying '.' as dir browses to My Computer) */
1112 if (handledPath
==FALSE
) {
1113 WCHAR tmpBuf
[MAX_PATH
];
1114 WCHAR tmpBuf2
[MAX_PATH
];
1118 strcpyW(tmpBuf
, fodInfos
->initdir
);
1119 if (tmpBuf
[strlenW(tmpBuf
)-1] != '\\') {
1120 strcatW(tmpBuf
, szwSlash
);
1122 strcatW(tmpBuf
, szwStar
);
1123 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1126 if (fodInfos
->initdir
)
1127 MemFree(fodInfos
->initdir
);
1128 fodInfos
->initdir
= MemAlloc((strlenW(tmpBuf2
) + 1)*sizeof(WCHAR
));
1129 strcpyW(fodInfos
->initdir
, tmpBuf2
);
1131 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1136 if ((handledPath
== FALSE
) && ((fodInfos
->initdir
==NULL
) ||
1137 (*fodInfos
->initdir
==0x00)))
1139 /* 3. All except w2k+: if filename contains a path use it */
1140 if (!win2000plus
&& fodInfos
->filename
&&
1141 *fodInfos
->filename
&&
1142 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1143 WCHAR tmpBuf
[MAX_PATH
];
1147 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1152 /* nameBit is always shorter than the original filename */
1153 strcpyW(fodInfos
->filename
, nameBit
);
1156 len
= strlenW(tmpBuf
);
1157 if(fodInfos
->initdir
)
1158 MemFree(fodInfos
->initdir
);
1159 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1160 strcpyW(fodInfos
->initdir
, tmpBuf
);
1163 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1164 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1166 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1169 /* 4. win98+ and win2000+ if any files of specified filter types in
1170 current directory, use it */
1171 if ( win98plus
&& handledPath
== FALSE
&&
1172 fodInfos
->filter
&& *fodInfos
->filter
) {
1174 BOOL searchMore
= TRUE
;
1175 LPCWSTR lpstrPos
= fodInfos
->filter
;
1176 WIN32_FIND_DATAW FindFileData
;
1181 /* filter is a list... title\0ext\0......\0\0 */
1183 /* Skip the title */
1184 if(! *lpstrPos
) break; /* end */
1185 lpstrPos
+= strlenW(lpstrPos
) + 1;
1187 /* See if any files exist in the current dir with this extension */
1188 if(! *lpstrPos
) break; /* end */
1190 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1192 if (hFind
== INVALID_HANDLE_VALUE
) {
1193 /* None found - continue search */
1194 lpstrPos
+= strlenW(lpstrPos
) + 1;
1199 if(fodInfos
->initdir
)
1200 MemFree(fodInfos
->initdir
);
1201 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1202 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1205 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1206 debugstr_w(lpstrPos
));
1212 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1214 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1215 if (handledPath
== FALSE
&& (win2000plus
|| win98plus
)) {
1216 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1218 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
)))
1220 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
)))
1223 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1224 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1226 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1229 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1232 } else if (handledPath
==FALSE
) {
1233 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1234 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1236 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1239 TRACE("After manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1241 /* Must the open as read only check box be checked ?*/
1242 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1244 SendDlgItemMessageA(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,(WPARAM
)TRUE
,0);
1247 /* Must the open as read only check box be hid ?*/
1248 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1250 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1253 /* Must the help button be hid ?*/
1254 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1256 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1259 /* Resize the height, if open as read only checkbox ad help button
1260 are hidden and we are not using a custom template */
1261 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1262 (!(fodInfos
->ofnInfos
->Flags
&
1263 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1265 RECT rectDlg
, rectHelp
, rectCancel
;
1266 GetWindowRect(hwnd
, &rectDlg
);
1267 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1268 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1269 /* subtract the height of the help button plus the space between
1270 the help button and the cancel button to the height of the dialog */
1271 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1272 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1273 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1276 /* change Open to Save FIXME: use resources */
1277 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1279 SetDlgItemTextA(hwnd
,IDOK
,"&Save");
1280 SetDlgItemTextA(hwnd
,IDC_LOOKINSTATIC
,"Save &in");
1285 /***********************************************************************
1286 * FILEDLG95_FillControls
1288 * WM_INITDIALOG message handler (after hook notification)
1290 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1292 LPITEMIDLIST pidlItemId
= NULL
;
1294 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1296 TRACE("dir=%s file=%s\n",
1297 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1299 /* Get the initial directory pidl */
1301 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1303 WCHAR path
[MAX_PATH
];
1305 GetCurrentDirectoryW(MAX_PATH
,path
);
1306 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1309 /* Initialise shell objects */
1310 FILEDLG95_SHELL_Init(hwnd
);
1312 /* Initialize the Look In combo box */
1313 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1315 /* Initialize the filter combo box */
1316 FILEDLG95_FILETYPE_Init(hwnd
);
1318 /* Browse to the initial directory */
1319 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1321 /* Free pidlItem memory */
1322 COMDLG32_SHFree(pidlItemId
);
1326 /***********************************************************************
1329 * Regroups all the cleaning functions of the filedlg
1331 void FILEDLG95_Clean(HWND hwnd
)
1333 FILEDLG95_FILETYPE_Clean(hwnd
);
1334 FILEDLG95_LOOKIN_Clean(hwnd
);
1335 FILEDLG95_SHELL_Clean(hwnd
);
1337 /***********************************************************************
1338 * FILEDLG95_OnWMCommand
1340 * WM_COMMAND message handler
1342 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1344 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1345 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1346 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1352 FILEDLG95_OnOpen(hwnd
);
1356 FILEDLG95_Clean(hwnd
);
1357 EndDialog(hwnd
, FALSE
);
1359 /* Filetype combo box */
1361 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1363 /* LookIn combo box */
1365 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1368 /* --- toolbar --- */
1369 /* Up folder button */
1370 case FCIDM_TB_UPFOLDER
:
1371 FILEDLG95_SHELL_UpFolder(hwnd
);
1373 /* New folder button */
1374 case FCIDM_TB_NEWFOLDER
:
1375 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDER
);
1377 /* List option button */
1378 case FCIDM_TB_SMALLICON
:
1379 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLIST
);
1381 /* Details option button */
1382 case FCIDM_TB_REPORTVIEW
:
1383 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILS
);
1385 /* Details option button */
1386 case FCIDM_TB_DESKTOP
:
1387 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1394 /* Do not use the listview selection anymore */
1395 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1399 /***********************************************************************
1400 * FILEDLG95_OnWMGetIShellBrowser
1402 * WM_GETISHELLBROWSER message handler
1404 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1407 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1411 SetWindowLongA(hwnd
,DWL_MSGRESULT
,(LONG
)fodInfos
->Shell
.FOIShellBrowser
);
1417 /***********************************************************************
1418 * FILEDLG95_SendFileOK
1420 * Sends the CDN_FILEOK notification if required
1423 * TRUE if the dialog should close
1424 * FALSE if the dialog should not be closed
1426 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1428 /* ask the hook if we can close */
1429 if(IsHooked(fodInfos
))
1432 /* First send CDN_FILEOK as MSDN doc says */
1433 SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1435 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1436 CallWindowProcA((WNDPROC
)fodInfos
->ofnInfos
->lpfnHook
,
1437 fodInfos
->DlgInfos
.hwndCustomDlg
,
1438 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1439 if (GetWindowLongA(fodInfos
->DlgInfos
.hwndCustomDlg
, DWL_MSGRESULT
))
1441 TRACE("canceled\n");
1448 /***********************************************************************
1449 * FILEDLG95_OnOpenMultipleFiles
1451 * Handles the opening of multiple files.
1454 * check destination buffer size
1456 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1458 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1459 UINT nCount
, nSizePath
;
1460 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1464 if(fodInfos
->unicode
)
1466 LPOPENFILENAMEW ofn
= (LPOPENFILENAMEW
) fodInfos
->ofnInfos
;
1467 ofn
->lpstrFile
[0] = '\0';
1471 LPOPENFILENAMEA ofn
= fodInfos
->ofnInfos
;
1472 ofn
->lpstrFile
[0] = '\0';
1475 SHGetPathFromIDListW( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
1477 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1478 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1479 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1481 LPWSTR lpstrTemp
= lpstrFileList
;
1483 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
1487 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
1490 WCHAR lpstrNotFound
[100];
1491 WCHAR lpstrMsg
[100];
1493 WCHAR nl
[] = {'\n',0};
1495 LoadStringW(COMMDLG_hInstance32
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
1496 LoadStringW(COMMDLG_hInstance32
, IDS_VERIFYFILE
, lpstrMsg
, 100);
1498 strcpyW(tmp
, lpstrTemp
);
1500 strcatW(tmp
, lpstrNotFound
);
1502 strcatW(tmp
, lpstrMsg
);
1504 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
1508 /* move to the next file in the list of files */
1509 lpstrTemp
+= strlenW(lpstrTemp
) + 1;
1510 COMDLG32_SHFree(pidl
);
1514 nSizePath
= strlenW(lpstrPathSpec
) + 1;
1515 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
1517 /* For "oldstyle" dialog the components have to
1518 be spearated by blanks (not '\0'!) and short
1519 filenames have to be used! */
1520 FIXME("Components have to be separated by blanks");
1522 if(fodInfos
->unicode
)
1524 LPOPENFILENAMEW ofn
= (LPOPENFILENAMEW
) fodInfos
->ofnInfos
;
1525 strcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
1526 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
1530 LPOPENFILENAMEA ofn
= fodInfos
->ofnInfos
;
1532 if (ofn
->lpstrFile
!= NULL
)
1534 WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
1535 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
1536 if (ofn
->nMaxFile
> nSizePath
)
1538 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
1539 ofn
->lpstrFile
+ nSizePath
,
1540 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
1545 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
+ 1;
1546 fodInfos
->ofnInfos
->nFileExtension
= 0;
1548 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
1551 /* clean and exit */
1552 FILEDLG95_Clean(hwnd
);
1553 return EndDialog(hwnd
,TRUE
);
1556 /***********************************************************************
1559 * Ok button WM_COMMAND message handler
1561 * If the function succeeds, the return value is nonzero.
1563 #define ONOPEN_BROWSE 1
1564 #define ONOPEN_OPEN 2
1565 #define ONOPEN_SEARCH 3
1566 static void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
1568 char strMsgTitle
[MAX_PATH
];
1569 char strMsgText
[MAX_PATH
];
1571 LoadStringA(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
));
1573 strMsgTitle
[0] = '\0';
1574 LoadStringA(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
));
1575 MessageBoxA(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
1578 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
1580 LPWSTR lpstrFileList
;
1581 UINT nFileCount
= 0;
1584 WCHAR lpstrPathAndFile
[MAX_PATH
];
1585 WCHAR lpstrTemp
[MAX_PATH
];
1586 LPSHELLFOLDER lpsf
= NULL
;
1588 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1590 TRACE("hwnd=0x%04x\n", hwnd
);
1592 /* get the files from the edit control */
1593 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
1595 /* try if the user selected a folder in the shellview */
1598 BrowseSelectedFolder(hwnd
);
1604 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
1608 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
1611 Step 1: Build a complete path name from the current folder and
1612 the filename or path in the edit box.
1614 - the path in the edit box is a root path
1615 (with or without drive letter)
1616 - the edit box contains ".." (or a path with ".." in it)
1619 /* Get the current directory name */
1620 if (!SHGetPathFromIDListW(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathAndFile
))
1622 /* we are in a special folder, default to desktop */
1623 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, lpstrPathAndFile
)))
1626 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
1629 PathAddBackslashW(lpstrPathAndFile
);
1631 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
1633 /* if the user specifyed a fully qualified path use it */
1634 if(PathIsRelativeW(lpstrFileList
))
1636 strcatW(lpstrPathAndFile
, lpstrFileList
);
1640 /* does the path have a drive letter? */
1641 if (PathGetDriveNumberW(lpstrFileList
) == -1)
1642 strcpyW(lpstrPathAndFile
+2, lpstrFileList
);
1644 strcpyW(lpstrPathAndFile
, lpstrFileList
);
1647 /* resolve "." and ".." */
1648 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
1649 strcpyW(lpstrPathAndFile
, lpstrTemp
);
1650 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
1652 MemFree(lpstrFileList
);
1655 Step 2: here we have a cleaned up path
1657 We have to parse the path step by step to see if we have to browse
1658 to a folder if the path points to a directory or the last
1659 valid element is a directory.
1662 lpstrPathAndFile: cleaned up path
1665 nOpenAction
= ONOPEN_BROWSE
;
1667 /* dont apply any checks with OFN_NOVALIDATE */
1669 LPWSTR lpszTemp
, lpszTemp1
;
1670 LPITEMIDLIST pidl
= NULL
;
1671 WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
1673 /* check for invalid chars */
1674 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1676 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
1681 if (FAILED (SHGetDesktopFolder(&lpsf
))) return FALSE
;
1683 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
1686 LPSHELLFOLDER lpsfChild
;
1687 WCHAR lpwstrTemp
[MAX_PATH
];
1688 DWORD dwEaten
, dwAttributes
;
1691 strcpyW(lpwstrTemp
, lpszTemp
);
1692 p
= PathFindNextComponentW(lpwstrTemp
);
1694 if (!p
) break; /* end of path */
1697 lpszTemp
= lpszTemp
+ strlenW(lpwstrTemp
);
1701 WCHAR wszWild
[] = { '*', '?', 0 };
1702 /* if the last element is a wildcard do a search */
1703 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
1705 nOpenAction
= ONOPEN_SEARCH
;
1709 lpszTemp1
= lpszTemp
;
1711 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), lpsf
);
1713 if(lstrlenW(lpwstrTemp
)==2) PathAddBackslashW(lpwstrTemp
);
1715 dwAttributes
= SFGAO_FOLDER
;
1716 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
1718 /* the path component is valid, we have a pidl of the next path component */
1719 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes
, pidl
);
1720 if(dwAttributes
& SFGAO_FOLDER
)
1722 if(FAILED(IShellFolder_BindToObject(lpsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
1724 ERR("bind to failed\n"); /* should not fail */
1727 IShellFolder_Release(lpsf
);
1735 /* end dialog, return value */
1736 nOpenAction
= ONOPEN_OPEN
;
1739 COMDLG32_SHFree(pidl
);
1742 else if (!(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1744 if(*lpszTemp
) /* points to trailing null for last path element */
1746 if(fodInfos
->ofnInfos
->Flags
& OFN_PATHMUSTEXIST
)
1748 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
1754 if( (fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1755 !( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1757 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
1761 /* change to the current folder */
1762 nOpenAction
= ONOPEN_OPEN
;
1767 nOpenAction
= ONOPEN_OPEN
;
1771 if(pidl
) COMDLG32_SHFree(pidl
);
1775 Step 3: here we have a cleaned up and validated path
1778 lpsf: ShellFolder bound to the rightmost valid path component
1779 lpstrPathAndFile: cleaned up path
1780 nOpenAction: action to do
1782 TRACE("end validate sf=%p\n", lpsf
);
1786 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
1787 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
1790 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
1793 /* replace the current filter */
1794 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
1795 MemFree((LPVOID
)fodInfos
->ShellInfos
.lpstrCurrentFilter
);
1796 len
= strlenW(lpszTemp
)+1;
1797 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
1798 strcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
1800 /* set the filter cb to the extension when possible */
1801 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
1802 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
1805 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
1806 TRACE("ONOPEN_BROWSE\n");
1808 IPersistFolder2
* ppf2
;
1809 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
1811 LPITEMIDLIST pidlCurrent
;
1812 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
1813 IPersistFolder2_Release(ppf2
);
1814 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
1816 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
);
1818 else if( nOpenAction
== ONOPEN_SEARCH
)
1820 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
1822 COMDLG32_SHFree(pidlCurrent
);
1827 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
1828 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
1830 /* add default extension */
1831 if (fodInfos
->defext
)
1833 if (! *PathFindExtensionW(lpstrPathAndFile
))
1835 /* only add "." in case a default extension does exist */
1836 if (*fodInfos
->defext
!= '\0')
1838 const WCHAR szwDot
[] = {'.',0};
1839 int PathLength
= strlenW(lpstrPathAndFile
);
1841 strcatW(lpstrPathAndFile
, szwDot
);
1842 strcatW(lpstrPathAndFile
, fodInfos
->defext
);
1844 /* if file does not exist try without extension */
1845 if (!PathFileExistsW(lpstrPathAndFile
))
1846 lpstrPathAndFile
[PathLength
] = '\0';
1851 /* Check that the size of the file does not exceed buffer size.
1852 (Allow for extra \0 if OFN_MULTISELECT is set.) */
1853 if(strlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
1854 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
1858 /* fill destination buffer */
1859 if (fodInfos
->ofnInfos
->lpstrFile
)
1861 if(fodInfos
->unicode
)
1863 LPOPENFILENAMEW ofn
= (LPOPENFILENAMEW
) fodInfos
->ofnInfos
;
1865 strncpyW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
1866 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
1867 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
1871 LPOPENFILENAMEA ofn
= fodInfos
->ofnInfos
;
1873 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
1874 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
1875 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
1876 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
1880 /* set filename offset */
1881 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
1882 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
1884 /* set extension offset */
1885 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
1886 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
1888 /* set the lpstrFileTitle */
1889 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
1891 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
1892 if(fodInfos
->unicode
)
1894 LPOPENFILENAMEW ofn
= (LPOPENFILENAMEW
) fodInfos
->ofnInfos
;
1895 strncpyW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
1899 LPOPENFILENAMEA ofn
= fodInfos
->ofnInfos
;
1900 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
1901 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
1905 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
1909 FILEDLG95_Clean(hwnd
);
1910 ret
= EndDialog(hwnd
, TRUE
);
1914 /* FIXME set error FNERR_BUFFERTOSMALL */
1915 FILEDLG95_Clean(hwnd
);
1916 ret
= EndDialog(hwnd
, FALSE
);
1924 if(lpsf
) IShellFolder_Release(lpsf
);
1928 /***********************************************************************
1929 * FILEDLG95_SHELL_Init
1931 * Initialisation of the shell objects
1933 static HRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
1935 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1940 * Initialisation of the FileOpenDialogInfos structure
1946 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
1948 /* Disable multi-select if flag not set */
1949 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
1951 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
1953 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
1954 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
1956 GetWindowRect(GetDlgItem(hwnd
,IDC_SHELLSTATIC
),&fodInfos
->ShellInfos
.rectView
);
1957 ScreenToClient(hwnd
,(LPPOINT
)&fodInfos
->ShellInfos
.rectView
.left
);
1958 ScreenToClient(hwnd
,(LPPOINT
)&fodInfos
->ShellInfos
.rectView
.right
);
1960 /* Construct the IShellBrowser interface */
1961 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
1966 /***********************************************************************
1967 * FILEDLG95_SHELL_ExecuteCommand
1969 * Change the folder option and refresh the view
1970 * If the function succeeds, the return value is nonzero.
1972 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
1974 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1977 TRACE("(0x%08x,%p)\n", hwnd
, lpVerb
);
1979 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
1984 CMINVOKECOMMANDINFO ci
;
1985 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
1986 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
1990 IContextMenu_InvokeCommand(pcm
, &ci
);
1991 IContextMenu_Release(pcm
);
1997 /***********************************************************************
1998 * FILEDLG95_SHELL_UpFolder
2000 * Browse to the specified object
2001 * If the function succeeds, the return value is nonzero.
2003 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2005 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2009 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2018 /***********************************************************************
2019 * FILEDLG95_SHELL_BrowseToDesktop
2021 * Browse to the Desktop
2022 * If the function succeeds, the return value is nonzero.
2024 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2026 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2032 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2033 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2034 COMDLG32_SHFree(pidl
);
2035 return SUCCEEDED(hres
);
2037 /***********************************************************************
2038 * FILEDLG95_SHELL_Clean
2040 * Cleans the memory used by shell objects
2042 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2044 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2048 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2050 /* clean Shell interfaces */
2051 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2052 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2053 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2054 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2055 if (fodInfos
->Shell
.FOIDataObject
)
2056 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2059 /***********************************************************************
2060 * FILEDLG95_FILETYPE_Init
2062 * Initialisation of the file type combo box
2064 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2066 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2070 if(fodInfos
->filter
)
2072 int nFilters
= 0; /* number of filters */
2074 LPCWSTR lpstrPos
= fodInfos
->filter
;
2078 /* filter is a list... title\0ext\0......\0\0
2079 * Set the combo item text to the title and the item data
2082 LPCWSTR lpstrDisplay
;
2086 if(! *lpstrPos
) break; /* end */
2087 lpstrDisplay
= lpstrPos
;
2088 lpstrPos
+= strlenW(lpstrPos
) + 1;
2090 /* Copy the extensions */
2091 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2092 if (!(lpstrExt
= MemAlloc((strlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2093 strcpyW(lpstrExt
,lpstrPos
);
2094 lpstrPos
+= strlenW(lpstrPos
) + 1;
2096 /* Add the item at the end of the combo */
2097 CBAddStringW(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2098 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2102 * Set the current filter to the one specified
2103 * in the initialisation structure
2104 * FIXME: lpstrCustomFilter not handled at all
2107 /* set default filter index */
2108 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
2109 fodInfos
->ofnInfos
->nFilterIndex
= 1;
2111 /* First, check to make sure our index isn't out of bounds. */
2112 if ( fodInfos
->ofnInfos
->nFilterIndex
> nFilters
)
2113 fodInfos
->ofnInfos
->nFilterIndex
= nFilters
;
2115 /* Set the current index selection. */
2116 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->ofnInfos
->nFilterIndex
-1);
2118 /* Get the corresponding text string from the combo box. */
2119 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2120 fodInfos
->ofnInfos
->nFilterIndex
-1);
2122 if ((INT
)lpstrFilter
== CB_ERR
) /* control is empty */
2128 CharLowerW(lpstrFilter
); /* lowercase */
2129 len
= strlenW(lpstrFilter
)+1;
2130 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2131 strcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2137 /***********************************************************************
2138 * FILEDLG95_FILETYPE_OnCommand
2140 * WM_COMMAND of the file type combo box
2141 * If the function succeeds, the return value is nonzero.
2143 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2145 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2153 /* Get the current item of the filetype combo box */
2154 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2156 /* set the current filter index - indexed from 1 */
2157 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+ 1;
2159 /* Set the current filter with the current selection */
2160 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
2161 MemFree((LPVOID
)fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2163 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2165 if((int)lpstrFilter
!= CB_ERR
)
2168 CharLowerW(lpstrFilter
); /* lowercase */
2169 len
= strlenW(lpstrFilter
)+1;
2170 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2171 strcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2172 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
2175 /* Refresh the actual view to display the included items*/
2176 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2181 /***********************************************************************
2182 * FILEDLG95_FILETYPE_SearchExt
2184 * searches for a extension in the filetype box
2186 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
2188 int i
, iCount
= CBGetCount(hwnd
);
2190 TRACE("%s\n", debugstr_w(lpstrExt
));
2192 if(iCount
!= CB_ERR
)
2194 for(i
=0;i
<iCount
;i
++)
2196 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
2203 /***********************************************************************
2204 * FILEDLG95_FILETYPE_Clean
2206 * Clean the memory used by the filetype combo box
2208 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
2210 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2212 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2216 /* Delete each string of the combo and their associated data */
2217 if(iCount
!= CB_ERR
)
2219 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
2221 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
2222 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
2225 /* Current filter */
2226 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
2227 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2231 /***********************************************************************
2232 * FILEDLG95_LOOKIN_Init
2234 * Initialisation of the look in combo box
2236 static HRESULT
FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
2238 IShellFolder
*psfRoot
, *psfDrives
;
2239 IEnumIDList
*lpeRoot
, *lpeDrives
;
2240 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
2242 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
2246 liInfos
->iMaxIndentation
= 0;
2248 SetPropA(hwndCombo
, LookInInfosStr
, (HANDLE
) liInfos
);
2250 /* set item height for both text field and listbox */
2251 CBSetItemHeight(hwndCombo
,-1,GetSystemMetrics(SM_CYSMICON
));
2252 CBSetItemHeight(hwndCombo
,0,GetSystemMetrics(SM_CYSMICON
));
2254 /* Initialise data of Desktop folder */
2255 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
2256 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2257 COMDLG32_SHFree(pidlTmp
);
2259 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
2261 SHGetDesktopFolder(&psfRoot
);
2265 /* enumerate the contents of the desktop */
2266 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
2268 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
2270 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2272 /* special handling for CSIDL_DRIVES */
2273 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
2275 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
2277 /* enumerate the drives */
2278 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
2280 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
2282 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
2283 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
2284 COMDLG32_SHFree(pidlAbsTmp
);
2285 COMDLG32_SHFree(pidlTmp1
);
2287 IEnumIDList_Release(lpeDrives
);
2289 IShellFolder_Release(psfDrives
);
2292 COMDLG32_SHFree(pidlTmp
);
2294 IEnumIDList_Release(lpeRoot
);
2298 IShellFolder_Release(psfRoot
);
2299 COMDLG32_SHFree(pidlDrives
);
2303 /***********************************************************************
2304 * FILEDLG95_LOOKIN_DrawItem
2306 * WM_DRAWITEM message handler
2308 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
2310 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
2311 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
2312 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
2316 HIMAGELIST ilItemImage
;
2319 LPSFOLDER tmpFolder
;
2322 LookInInfos
*liInfos
= (LookInInfos
*)GetPropA(pDIStruct
->hwndItem
,LookInInfosStr
);
2326 if(pDIStruct
->itemID
== -1)
2329 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
2330 pDIStruct
->itemID
)))
2334 if(pDIStruct
->itemID
== liInfos
->uSelectedItem
)
2336 ilItemImage
= (HIMAGELIST
) SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
2339 sizeof (SHFILEINFOA
),
2340 SHGFI_PIDL
| SHGFI_SMALLICON
|
2341 SHGFI_OPENICON
| SHGFI_SYSICONINDEX
|
2342 SHGFI_DISPLAYNAME
);
2346 ilItemImage
= (HIMAGELIST
) SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
2349 sizeof (SHFILEINFOA
),
2350 SHGFI_PIDL
| SHGFI_SMALLICON
|
2351 SHGFI_SYSICONINDEX
|
2355 /* Is this item selected ? */
2356 if(pDIStruct
->itemState
& ODS_SELECTED
)
2358 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
2359 SetBkColor(pDIStruct
->hDC
,crHighLight
);
2360 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
2364 SetTextColor(pDIStruct
->hDC
,crText
);
2365 SetBkColor(pDIStruct
->hDC
,crWin
);
2366 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
2369 /* Do not indent item if drawing in the edit of the combo */
2370 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
2373 ilItemImage
= (HIMAGELIST
) SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
2376 sizeof (SHFILEINFOA
),
2377 SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_OPENICON
2378 | SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
);
2383 iIndentation
= tmpFolder
->m_iIndent
;
2385 /* Draw text and icon */
2387 /* Initialise the icon display area */
2388 rectIcon
.left
= pDIStruct
->rcItem
.left
+ ICONWIDTH
/2 * iIndentation
;
2389 rectIcon
.top
= pDIStruct
->rcItem
.top
;
2390 rectIcon
.right
= rectIcon
.left
+ ICONWIDTH
;
2391 rectIcon
.bottom
= pDIStruct
->rcItem
.bottom
;
2393 /* Initialise the text display area */
2394 GetTextMetricsA(pDIStruct
->hDC
, &tm
);
2395 rectText
.left
= rectIcon
.right
;
2397 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
2398 rectText
.right
= pDIStruct
->rcItem
.right
+ XTEXTOFFSET
;
2400 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
2402 /* Draw the icon from the image list */
2403 ImageList_Draw(ilItemImage
,
2410 /* Draw the associated text */
2411 if(sfi
.szDisplayName
)
2412 TextOutA(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,strlen(sfi
.szDisplayName
));
2418 /***********************************************************************
2419 * FILEDLG95_LOOKIN_OnCommand
2421 * LookIn combo box WM_COMMAND message handler
2422 * If the function succeeds, the return value is nonzero.
2424 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2426 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2428 TRACE("%p\n", fodInfos
);
2434 LPSFOLDER tmpFolder
;
2437 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
2439 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
2444 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2445 tmpFolder
->pidlItem
,
2457 /***********************************************************************
2458 * FILEDLG95_LOOKIN_AddItem
2460 * Adds an absolute pidl item to the lookin combo box
2461 * returns the index of the inserted item
2463 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
2465 LPITEMIDLIST pidlNext
;
2468 LookInInfos
*liInfos
;
2470 TRACE("%08x\n", iInsertId
);
2475 if(!(liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
)))
2478 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
2479 tmpFolder
->m_iIndent
= 0;
2481 /* Calculate the indentation of the item in the lookin*/
2483 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
2485 tmpFolder
->m_iIndent
++;
2488 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
2490 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
2491 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
2493 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
2494 SHGetFileInfoA((LPSTR
)pidl
,
2498 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
2499 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
2501 TRACE("-- Add %s attr=%08lx\n", sfi
.szDisplayName
, sfi
.dwAttributes
);
2503 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
2507 TRACE("-- Add %s at %u\n", sfi
.szDisplayName
, tmpFolder
->m_iIndent
);
2509 /* Add the item at the end of the list */
2512 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
2514 /* Insert the item at the iInsertId position*/
2517 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
2520 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
2524 COMDLG32_SHFree( tmpFolder
->pidlItem
);
2525 MemFree( tmpFolder
);
2530 /***********************************************************************
2531 * FILEDLG95_LOOKIN_InsertItemAfterParent
2533 * Insert an item below its parent
2535 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
2538 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
2543 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
2547 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
2550 /* Free pidlParent memory */
2551 COMDLG32_SHFree((LPVOID
)pidlParent
);
2553 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
2556 /***********************************************************************
2557 * FILEDLG95_LOOKIN_SelectItem
2559 * Adds an absolute pidl item to the lookin combo box
2560 * returns the index of the inserted item
2562 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
2565 LookInInfos
*liInfos
;
2569 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
2571 liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
);
2575 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
2576 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
2581 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
2582 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
2586 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
2588 if(iRemovedItem
< iItemPos
)
2593 CBSetCurSel(hwnd
,iItemPos
);
2594 liInfos
->uSelectedItem
= iItemPos
;
2600 /***********************************************************************
2601 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2603 * Remove the item with an expansion level over iExpansionLevel
2605 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
2609 LookInInfos
*liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
);
2613 if(liInfos
->iMaxIndentation
<= 2)
2616 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
2618 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
2619 COMDLG32_SHFree(tmpFolder
->pidlItem
);
2621 CBDeleteString(hwnd
,iItemPos
);
2622 liInfos
->iMaxIndentation
--;
2630 /***********************************************************************
2631 * FILEDLG95_LOOKIN_SearchItem
2633 * Search for pidl in the lookin combo box
2634 * returns the index of the found item
2636 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
2639 int iCount
= CBGetCount(hwnd
);
2641 TRACE("0x%08x 0x%x\n",searchArg
, iSearchMethod
);
2643 if (iCount
!= CB_ERR
)
2647 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
2649 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
2651 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
2659 /***********************************************************************
2660 * FILEDLG95_LOOKIN_Clean
2662 * Clean the memory used by the lookin combo box
2664 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
2666 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2668 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
2672 /* Delete each string of the combo and their associated data */
2673 if (iCount
!= CB_ERR
)
2675 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
2677 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
2678 COMDLG32_SHFree(tmpFolder
->pidlItem
);
2680 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
2684 /* LookInInfos structure */
2685 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
2688 /***********************************************************************
2689 * FILEDLG95_FILENAME_FillFromSelection
2691 * fills the edit box from the cached DataObject
2693 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
2695 FileOpenDlgInfos
*fodInfos
;
2697 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nLength
= 0;
2698 char lpstrTemp
[MAX_PATH
];
2699 LPSTR lpstrAllFile
= NULL
, lpstrCurrFile
= NULL
;
2702 fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2704 /* Count how many files we have */
2705 nFileSelected
= GetNumSelected( fodInfos
->Shell
.FOIDataObject
);
2707 /* calculate the string length, count files */
2708 if (nFileSelected
>= 1)
2710 nLength
+= 3; /* first and last quotes, trailing \0 */
2711 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
2713 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
2717 /* get the total length of the selected file names*/
2718 lpstrTemp
[0] = '\0';
2719 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
2721 if ( ! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
) ) /* Ignore folders */
2723 nLength
+= strlen( lpstrTemp
) + 3;
2726 COMDLG32_SHFree( pidl
);
2731 /* allocate the buffer */
2732 if (nFiles
<= 1) nLength
= MAX_PATH
;
2733 lpstrAllFile
= (LPSTR
)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nLength
);
2734 lpstrAllFile
[0] = '\0';
2736 /* Generate the string for the edit control */
2739 lpstrCurrFile
= lpstrAllFile
;
2740 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
2742 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
2746 /* get the file name */
2747 lpstrTemp
[0] = '\0';
2748 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
2750 if (! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
)) /* Ignore folders */
2754 *lpstrCurrFile
++ = '\"';
2755 strcpy( lpstrCurrFile
, lpstrTemp
);
2756 lpstrCurrFile
+= strlen( lpstrTemp
);
2757 strcpy( lpstrCurrFile
, "\" " );
2762 strcpy( lpstrAllFile
, lpstrTemp
);
2765 COMDLG32_SHFree( (LPVOID
) pidl
);
2768 SetWindowTextA( fodInfos
->DlgInfos
.hwndFileName
, lpstrAllFile
);
2770 HeapFree(GetProcessHeap(),0, lpstrAllFile
);
2774 /* copied from shell32 to avoid linking to it */
2775 static HRESULT
COMDLG32_StrRetToStrNA (LPVOID dest
, DWORD len
, LPSTRRET src
, LPITEMIDLIST pidl
)
2780 WideCharToMultiByte(CP_ACP
, 0, src
->u
.pOleStr
, -1, (LPSTR
)dest
, len
, NULL
, NULL
);
2781 COMDLG32_SHFree(src
->u
.pOleStr
);
2785 lstrcpynA((LPSTR
)dest
, src
->u
.cStr
, len
);
2789 lstrcpynA((LPSTR
)dest
, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, len
);
2793 FIXME("unknown type!\n");
2796 *(LPSTR
)dest
= '\0';
2803 /***********************************************************************
2804 * FILEDLG95_FILENAME_GetFileNames
2806 * copies the filenames to a 0-delimited string list (A\0B\0C\0\0)
2808 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
2810 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2811 UINT nStrCharCount
= 0; /* index in src buffer */
2812 UINT nFileIndex
= 0; /* index in dest buffer */
2813 UINT nFileCount
= 0; /* number of files */
2814 UINT nStrLen
= 0; /* length of string in edit control */
2815 LPWSTR lpstrEdit
; /* buffer for string from edit control */
2819 /* get the filenames from the edit control */
2820 nStrLen
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0);
2821 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
2822 GetDlgItemTextW(hwnd
, IDC_FILENAME
, lpstrEdit
, nStrLen
+1);
2824 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
2826 /* we might get single filename without any '"',
2827 * so we need nStrLen + terminating \0 + end-of-list \0 */
2828 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
2831 /* build 0-delimited file list from filenames */
2832 while ( nStrCharCount
<= nStrLen
)
2834 if ( lpstrEdit
[nStrCharCount
]=='"' )
2837 while ((lpstrEdit
[nStrCharCount
]!='"') && (nStrCharCount
<= nStrLen
))
2839 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
2843 (*lpstrFileList
)[nFileIndex
++] = '\0';
2850 /* single, unquoted string */
2851 if ((nStrLen
> 0) && (*sizeUsed
== 0) )
2853 strcpyW(*lpstrFileList
, lpstrEdit
);
2854 nFileIndex
= strlenW(lpstrEdit
) + 1;
2855 (*sizeUsed
) = nFileIndex
;
2860 (*lpstrFileList
)[nFileIndex
] = '\0';
2867 #define SETDefFormatEtc(fe,cf,med) \
2869 (fe).cfFormat = cf;\
2870 (fe).dwAspect = DVASPECT_CONTENT; \
2877 * DATAOBJECT Helper functions
2880 /***********************************************************************
2881 * COMCTL32_ReleaseStgMedium
2883 * like ReleaseStgMedium from ole32
2885 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
2887 if(medium
.pUnkForRelease
)
2889 IUnknown_Release(medium
.pUnkForRelease
);
2893 GlobalUnlock(medium
.u
.hGlobal
);
2894 GlobalFree(medium
.u
.hGlobal
);
2898 /***********************************************************************
2899 * GetPidlFromDataObject
2901 * Return pidl(s) by number from the cached DataObject
2903 * nPidlIndex=0 gets the fully qualified root path
2905 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
2909 FORMATETC formatetc
;
2910 LPITEMIDLIST pidl
= NULL
;
2912 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
2914 /* Set the FORMATETC structure*/
2915 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
2917 /* Get the pidls from IDataObject */
2918 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
2920 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
2921 if(nPidlIndex
<= cida
->cidl
)
2923 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
2925 COMCTL32_ReleaseStgMedium(medium
);
2930 /***********************************************************************
2933 * Return the number of selected items in the DataObject.
2936 UINT
GetNumSelected( IDataObject
*doSelected
)
2940 FORMATETC formatetc
;
2942 TRACE("sv=%p\n", doSelected
);
2944 if (!doSelected
) return 0;
2946 /* Set the FORMATETC structure*/
2947 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
2949 /* Get the pidls from IDataObject */
2950 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
2952 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
2953 retVal
= cida
->cidl
;
2954 COMCTL32_ReleaseStgMedium(medium
);
2964 /***********************************************************************
2967 * Get the pidl's display name (relative to folder) and
2968 * put it in lpstrFileName.
2970 * Return NOERROR on success,
2974 HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPSTR lpstrFileName
)
2979 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
2984 SHGetDesktopFolder(&lpsf
);
2985 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
2986 IShellFolder_Release(lpsf
);
2990 /* Get the display name of the pidl relative to the folder */
2991 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
2993 return COMDLG32_StrRetToStrNA(lpstrFileName
, MAX_PATH
, &str
, pidl
);
2998 /***********************************************************************
2999 * GetShellFolderFromPidl
3001 * pidlRel is the item pidl relative
3002 * Return the IShellFolder of the absolute pidl
3004 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3006 IShellFolder
*psf
= NULL
,*psfParent
;
3008 TRACE("%p\n", pidlAbs
);
3010 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3013 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3015 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3017 IShellFolder_Release(psfParent
);
3021 /* return the desktop */
3027 /***********************************************************************
3030 * Return the LPITEMIDLIST to the parent of the pidl in the list
3032 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3034 LPITEMIDLIST pidlParent
;
3036 TRACE("%p\n", pidl
);
3038 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3039 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3044 /***********************************************************************
3047 * returns the pidl of the file name relative to folder
3048 * NULL if an error occurred
3050 LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3052 LPITEMIDLIST pidl
= NULL
;
3055 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3057 if(!lpcstrFileName
) return NULL
;
3058 if(!*lpcstrFileName
) return NULL
;
3062 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3063 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3064 IShellFolder_Release(lpsf
);
3069 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3076 BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPITEMIDLIST pidl
)
3078 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3081 TRACE("%p, %p\n", psf
, pidl
);
3083 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3085 TRACE("-- 0x%08lx 0x%08lx\n", uAttr
, ret
);
3086 /* see documentation shell 4.1*/
3087 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3090 /***********************************************************************
3091 * BrowseSelectedFolder
3093 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3095 BOOL bBrowseSelFolder
= FALSE
;
3096 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
3100 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3102 LPITEMIDLIST pidlSelection
;
3104 /* get the file selected */
3105 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
3106 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
3108 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
3109 pidlSelection
, SBSP_RELATIVE
) ) )
3111 WCHAR notexist
[] = {'P','a','t','h',' ','d','o','e','s',
3112 ' ','n','o','t',' ','e','x','i','s','t',0};
3113 MessageBoxW( hwnd
, notexist
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
3116 bBrowseSelFolder
= TRUE
;
3118 COMDLG32_SHFree( pidlSelection
);
3121 return bBrowseSelFolder
;
3125 * Memory allocation methods */
3126 static void *MemAlloc(UINT size
)
3128 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
3131 static void MemFree(void *mem
)
3135 HeapFree(GetProcessHeap(),0,mem
);