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 /***********************************************************************
796 * FILEDLG95_HandleCustomDialogMessages
798 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
800 HRESULT
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
804 char lpstrPath
[MAX_PATH
];
805 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
806 if(!fodInfos
) return -1;
810 case CDM_GETFILEPATH
:
811 GetDlgItemTextA(hwnd
,IDC_FILENAME
,lpstrPath
, sizeof(lpstrPath
));
812 lpstrFileSpec
= (LPSTR
)PathFindFileNameA(lpstrPath
);
813 if (lpstrFileSpec
==lpstrPath
)
815 char lpstrCurrentDir
[MAX_PATH
];
816 /* Prepend the current path */
817 SHGetPathFromIDListA(fodInfos
->ShellInfos
.pidlAbsCurrent
,lpstrCurrentDir
);
818 if ((LPSTR
)lParam
!=NULL
)
819 snprintf((LPSTR
)lParam
,(int)wParam
,"%s\\%s",lpstrCurrentDir
,lpstrPath
);
820 reqSize
=strlen(lpstrCurrentDir
)+1+strlen(lpstrPath
)+1;
824 lstrcpynA((LPSTR
)lParam
,(LPSTR
)lpstrPath
,(int)wParam
);
825 reqSize
=strlen(lpstrPath
);
827 /* return the required buffer size */
830 case CDM_GETFOLDERPATH
:
831 SHGetPathFromIDListA(fodInfos
->ShellInfos
.pidlAbsCurrent
,lpstrPath
);
832 if ((LPSTR
)lParam
!=NULL
)
833 lstrcpynA((LPSTR
)lParam
,lpstrPath
,(int)wParam
);
834 return strlen(lpstrPath
);
837 reqSize
=GetDlgItemTextA(hwnd
,IDC_FILENAME
,lpstrPath
, sizeof(lpstrPath
));
838 lpstrFileSpec
= (LPSTR
)PathFindFileNameA(lpstrPath
);
839 if ((LPSTR
)lParam
!=NULL
)
840 lstrcpynA((LPSTR
)lParam
, lpstrFileSpec
, (int)wParam
);
841 return strlen(lpstrFileSpec
);
843 case CDM_SETCONTROLTEXT
:
845 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
848 case CDM_HIDECONTROL
:
850 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
856 /***********************************************************************
859 * File open dialog procedure
861 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
864 TRACE("0x%04x 0x%04x\n", hwnd
, uMsg
);
871 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
873 /* Adds the FileOpenDlgInfos in the property list of the dialog
874 so it will be easily accessible through a GetPropA(...) */
875 SetPropA(hwnd
, FileOpenDlgInfosStr
, (HANDLE
) fodInfos
);
877 fodInfos
->DlgInfos
.hwndCustomDlg
=
878 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
880 FILEDLG95_InitControls(hwnd
);
881 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
882 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
883 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
884 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
885 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
886 0,0,0,0, SWP_NOMOVE
|SWP_NOSIZE
);
890 return FILEDLG95_OnWMCommand(hwnd
, wParam
, lParam
);
893 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
896 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
902 case WM_GETISHELLBROWSER
:
903 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
906 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
911 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
914 /* set up the button tooltips strings */
915 if(TTN_GETDISPINFOA
== lpnmh
->code
)
917 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
918 switch(lpnmh
->idFrom
)
920 /* Up folder button */
921 case FCIDM_TB_UPFOLDER
:
922 stringId
= IDS_UPFOLDER
;
924 /* New folder button */
925 case FCIDM_TB_NEWFOLDER
:
926 stringId
= IDS_NEWFOLDER
;
928 /* List option button */
929 case FCIDM_TB_SMALLICON
:
930 stringId
= IDS_LISTVIEW
;
932 /* Details option button */
933 case FCIDM_TB_REPORTVIEW
:
934 stringId
= IDS_REPORTVIEW
;
937 case FCIDM_TB_DESKTOP
:
938 stringId
= IDS_TODESKTOP
;
943 lpdi
->hinst
= COMMDLG_hInstance32
;
944 lpdi
->lpszText
= (LPSTR
) stringId
;
949 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
950 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
955 /***********************************************************************
956 * FILEDLG95_InitControls
958 * WM_INITDIALOG message handler (before hook notification)
960 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
964 int handledPath
= FALSE
;
966 const WCHAR szwSlash
[] = { '\\', 0 };
967 const WCHAR szwStar
[] = { '*',0 };
971 {0, 0, TBSTATE_ENABLED
, TBSTYLE_SEP
, {0, 0}, 0, 0 },
972 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, TBSTYLE_BUTTON
, {0, 0}, 0, 0 },
973 {0, 0, TBSTATE_ENABLED
, TBSTYLE_SEP
, {0, 0}, 0, 0 },
974 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, TBSTYLE_BUTTON
, {0, 0}, 0, 0 },
975 {0, 0, TBSTATE_ENABLED
, TBSTYLE_SEP
, {0, 0}, 0, 0 },
976 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, TBSTYLE_BUTTON
, {0, 0}, 0, 0 },
977 {0, 0, TBSTATE_ENABLED
, TBSTYLE_SEP
, {0, 0}, 0, 0 },
978 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, TBSTYLE_BUTTON
, {0, 0}, 0, 0 },
979 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, TBSTYLE_BUTTON
, {0, 0}, 0, 0 },
983 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
985 tba
[0].hInst
= HINST_COMMCTRL
;
986 tba
[0].nID
= IDB_VIEW_SMALL_COLOR
;
987 tba
[1].hInst
= COMDLG32_hInstance
;
990 TRACE("%p\n", fodInfos
);
992 /* Get windows version emulating */
993 osVi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
994 GetVersionExA(&osVi
);
995 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
996 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
997 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
998 win2000plus
= (osVi
.dwMajorVersion
> 4);
999 if (win2000plus
) win98plus
= TRUE
;
1001 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1003 /* Get the hwnd of the controls */
1004 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem(hwnd
,IDC_FILENAME
);
1005 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1006 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1008 /* construct the toolbar */
1009 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1010 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1012 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, (LPSTR
) NULL
,
1013 WS_CHILD
| WS_GROUP
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1014 0, 0, 150, 26, hwnd
, (HMENU
) IDC_TOOLBAR
, COMMDLG_hInstance32
, NULL
);
1016 SetWindowPos(fodInfos
->DlgInfos
.hwndTB
, 0,
1017 rectTB
.left
,rectTB
.top
, rectTB
.right
-rectTB
.left
, rectTB
.bottom
-rectTB
.top
,
1018 SWP_SHOWWINDOW
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1020 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, (WPARAM
) sizeof(TBBUTTON
), 0);
1022 /* FIXME: use TB_LOADIMAGES when implemented */
1023 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1024 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, (WPARAM
) 12, (LPARAM
) &tba
[0]);
1025 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, (WPARAM
) 1, (LPARAM
) &tba
[1]);
1027 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSA
, (WPARAM
) 9,(LPARAM
) &tbb
);
1028 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1030 /* Set the window text with the text specified in the OPENFILENAME structure */
1033 SetWindowTextW(hwnd
,fodInfos
->title
);
1035 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1037 SetWindowTextA(hwnd
,"Save");
1040 /* Initialise the file name edit control */
1041 handledPath
= FALSE
;
1042 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1044 if(fodInfos
->filename
)
1046 /* 1. If win2000 or higher and filename contains a path, use it
1047 in preference over the lpstrInitialDir */
1048 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1049 WCHAR tmpBuf
[MAX_PATH
];
1053 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1056 /* nameBit is always shorter than the original filename */
1057 strcpyW(fodInfos
->filename
,nameBit
);
1060 if (fodInfos
->initdir
== NULL
)
1061 MemFree(fodInfos
->initdir
);
1062 fodInfos
->initdir
= MemAlloc((strlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1063 strcpyW(fodInfos
->initdir
, tmpBuf
);
1065 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1066 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1068 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1071 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1075 /* 2. (All platforms) If initdir is not null, then use it */
1076 if ((handledPath
== FALSE
) && (fodInfos
->initdir
!=NULL
) &&
1077 (*fodInfos
->initdir
!=0x00))
1079 /* Work out the proper path as supplied one might be relative */
1080 /* (Here because supplying '.' as dir browses to My Computer) */
1081 if (handledPath
==FALSE
) {
1082 WCHAR tmpBuf
[MAX_PATH
];
1083 WCHAR tmpBuf2
[MAX_PATH
];
1087 strcpyW(tmpBuf
, fodInfos
->initdir
);
1088 if (tmpBuf
[strlenW(tmpBuf
)-1] != '\\') {
1089 strcatW(tmpBuf
, szwSlash
);
1091 strcatW(tmpBuf
, szwStar
);
1092 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1095 if (fodInfos
->initdir
)
1096 MemFree(fodInfos
->initdir
);
1097 fodInfos
->initdir
= MemAlloc((strlenW(tmpBuf2
) + 1)*sizeof(WCHAR
));
1098 strcpyW(fodInfos
->initdir
, tmpBuf2
);
1100 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1105 if ((handledPath
== FALSE
) && ((fodInfos
->initdir
==NULL
) ||
1106 (*fodInfos
->initdir
==0x00)))
1108 /* 3. All except w2k+: if filename contains a path use it */
1109 if (!win2000plus
&& fodInfos
->filename
&&
1110 *fodInfos
->filename
&&
1111 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1112 WCHAR tmpBuf
[MAX_PATH
];
1116 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1121 /* nameBit is always shorter than the original filename */
1122 strcpyW(fodInfos
->filename
, nameBit
);
1125 len
= strlenW(tmpBuf
);
1126 if(fodInfos
->initdir
)
1127 MemFree(fodInfos
->initdir
);
1128 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1129 strcpyW(fodInfos
->initdir
, tmpBuf
);
1132 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1133 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1135 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1138 /* 4. win98+ and win2000+ if any files of specified filter types in
1139 current directory, use it */
1140 if ( win98plus
&& handledPath
== FALSE
&&
1141 fodInfos
->filter
&& *fodInfos
->filter
) {
1143 BOOL searchMore
= TRUE
;
1144 LPCWSTR lpstrPos
= fodInfos
->filter
;
1145 WIN32_FIND_DATAW FindFileData
;
1150 /* filter is a list... title\0ext\0......\0\0 */
1152 /* Skip the title */
1153 if(! *lpstrPos
) break; /* end */
1154 lpstrPos
+= strlenW(lpstrPos
) + 1;
1156 /* See if any files exist in the current dir with this extension */
1157 if(! *lpstrPos
) break; /* end */
1159 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1161 if (hFind
== INVALID_HANDLE_VALUE
) {
1162 /* None found - continue search */
1163 lpstrPos
+= strlenW(lpstrPos
) + 1;
1168 if(fodInfos
->initdir
)
1169 MemFree(fodInfos
->initdir
);
1170 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1171 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1174 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1175 debugstr_w(lpstrPos
));
1181 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1183 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1184 if (handledPath
== FALSE
&& (win2000plus
|| win98plus
)) {
1185 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1187 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
)))
1189 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
)))
1192 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1193 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1195 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1198 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1201 } else if (handledPath
==FALSE
) {
1202 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1203 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1205 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1208 TRACE("After manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1210 /* Must the open as read only check box be checked ?*/
1211 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1213 SendDlgItemMessageA(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,(WPARAM
)TRUE
,0);
1216 /* Must the open as read only check box be hid ?*/
1217 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1219 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1222 /* Must the help button be hid ?*/
1223 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1225 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1228 /* Resize the height, if open as read only checkbox ad help button
1229 are hidden and we are not using a custom template */
1230 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1231 (!(fodInfos
->ofnInfos
->Flags
&
1232 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1234 RECT rectDlg
, rectHelp
, rectCancel
;
1235 GetWindowRect(hwnd
, &rectDlg
);
1236 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1237 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1238 /* subtract the height of the help button plus the space between
1239 the help button and the cancel button to the height of the dialog */
1240 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1241 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1242 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1245 /* change Open to Save FIXME: use resources */
1246 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1248 SetDlgItemTextA(hwnd
,IDOK
,"&Save");
1249 SetDlgItemTextA(hwnd
,IDC_LOOKINSTATIC
,"Save &in");
1254 /***********************************************************************
1255 * FILEDLG95_FillControls
1257 * WM_INITDIALOG message handler (after hook notification)
1259 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1261 LPITEMIDLIST pidlItemId
= NULL
;
1263 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1265 TRACE("dir=%s file=%s\n",
1266 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1268 /* Get the initial directory pidl */
1270 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1272 WCHAR path
[MAX_PATH
];
1274 GetCurrentDirectoryW(MAX_PATH
,path
);
1275 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1278 /* Initialise shell objects */
1279 FILEDLG95_SHELL_Init(hwnd
);
1281 /* Initialize the Look In combo box */
1282 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1284 /* Initialize the filter combo box */
1285 FILEDLG95_FILETYPE_Init(hwnd
);
1287 /* Browse to the initial directory */
1288 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1290 /* Free pidlItem memory */
1291 COMDLG32_SHFree(pidlItemId
);
1295 /***********************************************************************
1298 * Regroups all the cleaning functions of the filedlg
1300 void FILEDLG95_Clean(HWND hwnd
)
1302 FILEDLG95_FILETYPE_Clean(hwnd
);
1303 FILEDLG95_LOOKIN_Clean(hwnd
);
1304 FILEDLG95_SHELL_Clean(hwnd
);
1306 /***********************************************************************
1307 * FILEDLG95_OnWMCommand
1309 * WM_COMMAND message handler
1311 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1313 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1314 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1315 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1321 FILEDLG95_OnOpen(hwnd
);
1325 FILEDLG95_Clean(hwnd
);
1326 EndDialog(hwnd
, FALSE
);
1328 /* Filetype combo box */
1330 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1332 /* LookIn combo box */
1334 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1337 /* --- toolbar --- */
1338 /* Up folder button */
1339 case FCIDM_TB_UPFOLDER
:
1340 FILEDLG95_SHELL_UpFolder(hwnd
);
1342 /* New folder button */
1343 case FCIDM_TB_NEWFOLDER
:
1344 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDER
);
1346 /* List option button */
1347 case FCIDM_TB_SMALLICON
:
1348 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLIST
);
1350 /* Details option button */
1351 case FCIDM_TB_REPORTVIEW
:
1352 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILS
);
1354 /* Details option button */
1355 case FCIDM_TB_DESKTOP
:
1356 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1363 /* Do not use the listview selection anymore */
1364 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1368 /***********************************************************************
1369 * FILEDLG95_OnWMGetIShellBrowser
1371 * WM_GETISHELLBROWSER message handler
1373 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1376 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1380 SetWindowLongA(hwnd
,DWL_MSGRESULT
,(LONG
)fodInfos
->Shell
.FOIShellBrowser
);
1386 /***********************************************************************
1387 * FILEDLG95_OnOpenMultipleFiles
1389 * Handles the opening of multiple files.
1392 * check destination buffer size
1394 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1396 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1397 UINT nCount
, nSizePath
;
1398 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1402 if(fodInfos
->unicode
)
1404 LPOPENFILENAMEW ofn
= (LPOPENFILENAMEW
) fodInfos
->ofnInfos
;
1405 ofn
->lpstrFile
[0] = '\0';
1409 LPOPENFILENAMEA ofn
= fodInfos
->ofnInfos
;
1410 ofn
->lpstrFile
[0] = '\0';
1413 SHGetPathFromIDListW( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
1415 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1416 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1417 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1419 LPWSTR lpstrTemp
= lpstrFileList
;
1421 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
1425 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
1428 WCHAR lpstrNotFound
[100];
1429 WCHAR lpstrMsg
[100];
1431 WCHAR nl
[] = {'\n',0};
1433 LoadStringW(COMMDLG_hInstance32
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
1434 LoadStringW(COMMDLG_hInstance32
, IDS_VERIFYFILE
, lpstrMsg
, 100);
1436 strcpyW(tmp
, lpstrTemp
);
1438 strcatW(tmp
, lpstrNotFound
);
1440 strcatW(tmp
, lpstrMsg
);
1442 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
1446 /* move to the next file in the list of files */
1447 lpstrTemp
+= strlenW(lpstrTemp
) + 1;
1448 COMDLG32_SHFree(pidl
);
1452 nSizePath
= strlenW(lpstrPathSpec
) + 1;
1453 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
1455 /* For "oldstyle" dialog the components have to
1456 be spearated by blanks (not '\0'!) and short
1457 filenames have to be used! */
1458 FIXME("Components have to be separated by blanks");
1460 if(fodInfos
->unicode
)
1462 LPOPENFILENAMEW ofn
= (LPOPENFILENAMEW
) fodInfos
->ofnInfos
;
1463 strcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
1464 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
1468 LPOPENFILENAMEA ofn
= fodInfos
->ofnInfos
;
1470 if (ofn
->lpstrFile
!= NULL
)
1472 WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
1473 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
1474 if (ofn
->nMaxFile
> nSizePath
)
1476 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
1477 ofn
->lpstrFile
+ nSizePath
,
1478 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
1483 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
+ 1;
1484 fodInfos
->ofnInfos
->nFileExtension
= 0;
1486 /* clean and exit */
1487 FILEDLG95_Clean(hwnd
);
1488 return EndDialog(hwnd
,TRUE
);
1491 /***********************************************************************
1494 * Ok button WM_COMMAND message handler
1496 * If the function succeeds, the return value is nonzero.
1498 #define ONOPEN_BROWSE 1
1499 #define ONOPEN_OPEN 2
1500 #define ONOPEN_SEARCH 3
1501 static void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
1503 char strMsgTitle
[MAX_PATH
];
1504 char strMsgText
[MAX_PATH
];
1506 LoadStringA(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
));
1508 strMsgTitle
[0] = '\0';
1509 LoadStringA(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
));
1510 MessageBoxA(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
1513 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
1515 LPWSTR lpstrFileList
;
1516 UINT nFileCount
= 0;
1519 WCHAR lpstrPathAndFile
[MAX_PATH
];
1520 WCHAR lpstrTemp
[MAX_PATH
];
1521 LPSHELLFOLDER lpsf
= NULL
;
1523 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1525 TRACE("hwnd=0x%04x\n", hwnd
);
1527 /* get the files from the edit control */
1528 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
1530 /* try if the user selected a folder in the shellview */
1533 BrowseSelectedFolder(hwnd
);
1539 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
1543 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
1546 Step 1: Build a complete path name from the current folder and
1547 the filename or path in the edit box.
1549 - the path in the edit box is a root path
1550 (with or without drive letter)
1551 - the edit box contains ".." (or a path with ".." in it)
1554 /* Get the current directory name */
1555 if (!SHGetPathFromIDListW(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathAndFile
))
1557 /* we are in a special folder, default to desktop */
1558 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, lpstrPathAndFile
)))
1561 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
1564 PathAddBackslashW(lpstrPathAndFile
);
1566 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
1568 /* if the user specifyed a fully qualified path use it */
1569 if(PathIsRelativeW(lpstrFileList
))
1571 strcatW(lpstrPathAndFile
, lpstrFileList
);
1575 /* does the path have a drive letter? */
1576 if (PathGetDriveNumberW(lpstrFileList
) == -1)
1577 strcpyW(lpstrPathAndFile
+2, lpstrFileList
);
1579 strcpyW(lpstrPathAndFile
, lpstrFileList
);
1582 /* resolve "." and ".." */
1583 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
1584 strcpyW(lpstrPathAndFile
, lpstrTemp
);
1585 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
1587 MemFree(lpstrFileList
);
1590 Step 2: here we have a cleaned up path
1592 We have to parse the path step by step to see if we have to browse
1593 to a folder if the path points to a directory or the last
1594 valid element is a directory.
1597 lpstrPathAndFile: cleaned up path
1600 nOpenAction
= ONOPEN_BROWSE
;
1602 /* dont apply any checks with OFN_NOVALIDATE */
1604 LPWSTR lpszTemp
, lpszTemp1
;
1605 LPITEMIDLIST pidl
= NULL
;
1606 WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
1608 /* check for invalid chars */
1609 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1611 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
1616 if (FAILED (SHGetDesktopFolder(&lpsf
))) return FALSE
;
1618 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
1621 LPSHELLFOLDER lpsfChild
;
1622 WCHAR lpwstrTemp
[MAX_PATH
];
1623 DWORD dwEaten
, dwAttributes
;
1626 strcpyW(lpwstrTemp
, lpszTemp
);
1627 p
= PathFindNextComponentW(lpwstrTemp
);
1629 if (!p
) break; /* end of path */
1632 lpszTemp
= lpszTemp
+ strlenW(lpwstrTemp
);
1636 WCHAR wszWild
[] = { '*', '?', 0 };
1637 /* if the last element is a wildcard do a search */
1638 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
1640 nOpenAction
= ONOPEN_SEARCH
;
1644 lpszTemp1
= lpszTemp
;
1646 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), lpsf
);
1648 if(lstrlenW(lpwstrTemp
)==2) PathAddBackslashW(lpwstrTemp
);
1650 dwAttributes
= SFGAO_FOLDER
;
1651 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
1653 /* the path component is valid, we have a pidl of the next path component */
1654 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes
, pidl
);
1655 if(dwAttributes
& SFGAO_FOLDER
)
1657 if(FAILED(IShellFolder_BindToObject(lpsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
1659 ERR("bind to failed\n"); /* should not fail */
1662 IShellFolder_Release(lpsf
);
1670 /* end dialog, return value */
1671 nOpenAction
= ONOPEN_OPEN
;
1674 COMDLG32_SHFree(pidl
);
1677 else if (!(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1679 if(*lpszTemp
) /* points to trailing null for last path element */
1681 if(fodInfos
->ofnInfos
->Flags
& OFN_PATHMUSTEXIST
)
1683 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
1689 if( (fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1690 !( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1692 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
1696 /* change to the current folder */
1697 nOpenAction
= ONOPEN_OPEN
;
1702 nOpenAction
= ONOPEN_OPEN
;
1706 if(pidl
) COMDLG32_SHFree(pidl
);
1710 Step 3: here we have a cleaned up and validated path
1713 lpsf: ShellFolder bound to the rightmost valid path component
1714 lpstrPathAndFile: cleaned up path
1715 nOpenAction: action to do
1717 TRACE("end validate sf=%p\n", lpsf
);
1721 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
1722 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
1725 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
1728 /* replace the current filter */
1729 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
1730 MemFree((LPVOID
)fodInfos
->ShellInfos
.lpstrCurrentFilter
);
1731 len
= strlenW(lpszTemp
)+1;
1732 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
1733 strcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
1735 /* set the filter cb to the extension when possible */
1736 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
1737 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
1740 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
1741 TRACE("ONOPEN_BROWSE\n");
1743 IPersistFolder2
* ppf2
;
1744 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
1746 LPITEMIDLIST pidlCurrent
;
1747 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
1748 IPersistFolder2_Release(ppf2
);
1749 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
1751 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
);
1753 else if( nOpenAction
== ONOPEN_SEARCH
)
1755 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
1757 COMDLG32_SHFree(pidlCurrent
);
1762 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
1763 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
1765 /* add default extension */
1766 if (fodInfos
->defext
)
1768 if (! *PathFindExtensionW(lpstrPathAndFile
))
1770 /* only add "." in case a default extension does exist */
1771 if (*fodInfos
->defext
!= '\0')
1773 const WCHAR szwDot
[] = {'.',0};
1774 int PathLength
= strlenW(lpstrPathAndFile
);
1776 strcatW(lpstrPathAndFile
, szwDot
);
1777 strcatW(lpstrPathAndFile
, fodInfos
->defext
);
1779 /* if file does not exist try without extension */
1780 if (!PathFileExistsW(lpstrPathAndFile
))
1781 lpstrPathAndFile
[PathLength
] = '\0';
1786 /* Check that the size of the file does not exceed buffer size.
1787 (Allow for extra \0 if OFN_MULTISELECT is set.) */
1788 if(strlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
1789 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
1793 /* fill destination buffer */
1794 if (fodInfos
->ofnInfos
->lpstrFile
)
1796 if(fodInfos
->unicode
)
1798 LPOPENFILENAMEW ofn
= (LPOPENFILENAMEW
) fodInfos
->ofnInfos
;
1800 strncpyW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
1801 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
1802 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
1806 LPOPENFILENAMEA ofn
= fodInfos
->ofnInfos
;
1808 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
1809 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
1810 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
1811 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
1815 /* set filename offset */
1816 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
1817 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
1819 /* set extension offset */
1820 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
1821 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
1823 /* set the lpstrFileTitle */
1824 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
1826 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
1827 if(fodInfos
->unicode
)
1829 LPOPENFILENAMEW ofn
= (LPOPENFILENAMEW
) fodInfos
->ofnInfos
;
1830 strncpyW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
1834 LPOPENFILENAMEA ofn
= fodInfos
->ofnInfos
;
1835 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
1836 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
1840 /* ask the hook if we can close */
1841 if(IsHooked(fodInfos
))
1844 /* First send CDN_FILEOK as MSDN doc says */
1845 SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1847 /* FIXME we are sending ASCII-structures. Does not work with NT */
1848 CallWindowProcA((WNDPROC
)fodInfos
->ofnInfos
->lpfnHook
,
1849 fodInfos
->DlgInfos
.hwndCustomDlg
,
1850 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1851 if (GetWindowLongA(fodInfos
->DlgInfos
.hwndCustomDlg
, DWL_MSGRESULT
))
1853 TRACE("canceled\n");
1860 FILEDLG95_Clean(hwnd
);
1861 ret
= EndDialog(hwnd
, TRUE
);
1865 /* FIXME set error FNERR_BUFFERTOSMALL */
1866 FILEDLG95_Clean(hwnd
);
1867 ret
= EndDialog(hwnd
, FALSE
);
1875 if(lpsf
) IShellFolder_Release(lpsf
);
1879 /***********************************************************************
1880 * FILEDLG95_SHELL_Init
1882 * Initialisation of the shell objects
1884 static HRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
1886 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1891 * Initialisation of the FileOpenDialogInfos structure
1897 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
1899 /* Disable multi-select if flag not set */
1900 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
1902 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
1904 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
1905 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
1907 GetWindowRect(GetDlgItem(hwnd
,IDC_SHELLSTATIC
),&fodInfos
->ShellInfos
.rectView
);
1908 ScreenToClient(hwnd
,(LPPOINT
)&fodInfos
->ShellInfos
.rectView
.left
);
1909 ScreenToClient(hwnd
,(LPPOINT
)&fodInfos
->ShellInfos
.rectView
.right
);
1911 /* Construct the IShellBrowser interface */
1912 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
1917 /***********************************************************************
1918 * FILEDLG95_SHELL_ExecuteCommand
1920 * Change the folder option and refresh the view
1921 * If the function succeeds, the return value is nonzero.
1923 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
1925 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1928 TRACE("(0x%08x,%p)\n", hwnd
, lpVerb
);
1930 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
1935 CMINVOKECOMMANDINFO ci
;
1936 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
1937 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
1941 IContextMenu_InvokeCommand(pcm
, &ci
);
1942 IContextMenu_Release(pcm
);
1948 /***********************************************************************
1949 * FILEDLG95_SHELL_UpFolder
1951 * Browse to the specified object
1952 * If the function succeeds, the return value is nonzero.
1954 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
1956 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1960 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
1969 /***********************************************************************
1970 * FILEDLG95_SHELL_BrowseToDesktop
1972 * Browse to the Desktop
1973 * If the function succeeds, the return value is nonzero.
1975 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
1977 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1983 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
1984 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
1985 COMDLG32_SHFree(pidl
);
1986 return SUCCEEDED(hres
);
1988 /***********************************************************************
1989 * FILEDLG95_SHELL_Clean
1991 * Cleans the memory used by shell objects
1993 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
1995 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1999 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2001 /* clean Shell interfaces */
2002 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2003 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2004 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2005 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2006 if (fodInfos
->Shell
.FOIDataObject
)
2007 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2010 /***********************************************************************
2011 * FILEDLG95_FILETYPE_Init
2013 * Initialisation of the file type combo box
2015 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2017 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2021 if(fodInfos
->filter
)
2023 int nFilters
= 0; /* number of filters */
2025 LPCWSTR lpstrPos
= fodInfos
->filter
;
2029 /* filter is a list... title\0ext\0......\0\0
2030 * Set the combo item text to the title and the item data
2033 LPCWSTR lpstrDisplay
;
2037 if(! *lpstrPos
) break; /* end */
2038 lpstrDisplay
= lpstrPos
;
2039 lpstrPos
+= strlenW(lpstrPos
) + 1;
2041 /* Copy the extensions */
2042 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2043 if (!(lpstrExt
= MemAlloc((strlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2044 strcpyW(lpstrExt
,lpstrPos
);
2045 lpstrPos
+= strlenW(lpstrPos
) + 1;
2047 /* Add the item at the end of the combo */
2048 CBAddStringW(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2049 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2053 * Set the current filter to the one specified
2054 * in the initialisation structure
2055 * FIXME: lpstrCustomFilter not handled at all
2058 /* set default filter index */
2059 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
2060 fodInfos
->ofnInfos
->nFilterIndex
= 1;
2062 /* First, check to make sure our index isn't out of bounds. */
2063 if ( fodInfos
->ofnInfos
->nFilterIndex
> nFilters
)
2064 fodInfos
->ofnInfos
->nFilterIndex
= nFilters
;
2066 /* Set the current index selection. */
2067 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->ofnInfos
->nFilterIndex
-1);
2069 /* Get the corresponding text string from the combo box. */
2070 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2071 fodInfos
->ofnInfos
->nFilterIndex
-1);
2073 if ((INT
)lpstrFilter
== CB_ERR
) /* control is empty */
2079 CharLowerW(lpstrFilter
); /* lowercase */
2080 len
= strlenW(lpstrFilter
)+1;
2081 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2082 strcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2088 /***********************************************************************
2089 * FILEDLG95_FILETYPE_OnCommand
2091 * WM_COMMAND of the file type combo box
2092 * If the function succeeds, the return value is nonzero.
2094 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2096 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2104 /* Get the current item of the filetype combo box */
2105 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2107 /* set the current filter index - indexed from 1 */
2108 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+ 1;
2110 /* Set the current filter with the current selection */
2111 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
2112 MemFree((LPVOID
)fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2114 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2116 if((int)lpstrFilter
!= CB_ERR
)
2119 CharLowerW(lpstrFilter
); /* lowercase */
2120 len
= strlenW(lpstrFilter
)+1;
2121 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2122 strcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2123 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
2126 /* Refresh the actual view to display the included items*/
2127 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2132 /***********************************************************************
2133 * FILEDLG95_FILETYPE_SearchExt
2135 * searches for a extension in the filetype box
2137 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
2139 int i
, iCount
= CBGetCount(hwnd
);
2141 TRACE("%s\n", debugstr_w(lpstrExt
));
2143 if(iCount
!= CB_ERR
)
2145 for(i
=0;i
<iCount
;i
++)
2147 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
2154 /***********************************************************************
2155 * FILEDLG95_FILETYPE_Clean
2157 * Clean the memory used by the filetype combo box
2159 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
2161 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2163 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2167 /* Delete each string of the combo and their associated data */
2168 if(iCount
!= CB_ERR
)
2170 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
2172 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
2173 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
2176 /* Current filter */
2177 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
2178 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2182 /***********************************************************************
2183 * FILEDLG95_LOOKIN_Init
2185 * Initialisation of the look in combo box
2187 static HRESULT
FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
2189 IShellFolder
*psfRoot
, *psfDrives
;
2190 IEnumIDList
*lpeRoot
, *lpeDrives
;
2191 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
2193 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
2197 liInfos
->iMaxIndentation
= 0;
2199 SetPropA(hwndCombo
, LookInInfosStr
, (HANDLE
) liInfos
);
2201 /* set item height for both text field and listbox */
2202 CBSetItemHeight(hwndCombo
,-1,GetSystemMetrics(SM_CYSMICON
));
2203 CBSetItemHeight(hwndCombo
,0,GetSystemMetrics(SM_CYSMICON
));
2205 /* Initialise data of Desktop folder */
2206 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
2207 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2208 COMDLG32_SHFree(pidlTmp
);
2210 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
2212 SHGetDesktopFolder(&psfRoot
);
2216 /* enumerate the contents of the desktop */
2217 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
2219 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
2221 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2223 /* special handling for CSIDL_DRIVES */
2224 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
2226 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
2228 /* enumerate the drives */
2229 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
2231 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
2233 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
2234 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
2235 COMDLG32_SHFree(pidlAbsTmp
);
2236 COMDLG32_SHFree(pidlTmp1
);
2238 IEnumIDList_Release(lpeDrives
);
2240 IShellFolder_Release(psfDrives
);
2243 COMDLG32_SHFree(pidlTmp
);
2245 IEnumIDList_Release(lpeRoot
);
2249 IShellFolder_Release(psfRoot
);
2250 COMDLG32_SHFree(pidlDrives
);
2254 /***********************************************************************
2255 * FILEDLG95_LOOKIN_DrawItem
2257 * WM_DRAWITEM message handler
2259 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
2261 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
2262 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
2263 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
2267 HIMAGELIST ilItemImage
;
2270 LPSFOLDER tmpFolder
;
2273 LookInInfos
*liInfos
= (LookInInfos
*)GetPropA(pDIStruct
->hwndItem
,LookInInfosStr
);
2277 if(pDIStruct
->itemID
== -1)
2280 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
2281 pDIStruct
->itemID
)))
2285 if(pDIStruct
->itemID
== liInfos
->uSelectedItem
)
2287 ilItemImage
= (HIMAGELIST
) SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
2290 sizeof (SHFILEINFOA
),
2291 SHGFI_PIDL
| SHGFI_SMALLICON
|
2292 SHGFI_OPENICON
| SHGFI_SYSICONINDEX
|
2293 SHGFI_DISPLAYNAME
);
2297 ilItemImage
= (HIMAGELIST
) SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
2300 sizeof (SHFILEINFOA
),
2301 SHGFI_PIDL
| SHGFI_SMALLICON
|
2302 SHGFI_SYSICONINDEX
|
2306 /* Is this item selected ? */
2307 if(pDIStruct
->itemState
& ODS_SELECTED
)
2309 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
2310 SetBkColor(pDIStruct
->hDC
,crHighLight
);
2311 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
2315 SetTextColor(pDIStruct
->hDC
,crText
);
2316 SetBkColor(pDIStruct
->hDC
,crWin
);
2317 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
2320 /* Do not indent item if drawing in the edit of the combo */
2321 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
2324 ilItemImage
= (HIMAGELIST
) SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
2327 sizeof (SHFILEINFOA
),
2328 SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_OPENICON
2329 | SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
);
2334 iIndentation
= tmpFolder
->m_iIndent
;
2336 /* Draw text and icon */
2338 /* Initialise the icon display area */
2339 rectIcon
.left
= pDIStruct
->rcItem
.left
+ ICONWIDTH
/2 * iIndentation
;
2340 rectIcon
.top
= pDIStruct
->rcItem
.top
;
2341 rectIcon
.right
= rectIcon
.left
+ ICONWIDTH
;
2342 rectIcon
.bottom
= pDIStruct
->rcItem
.bottom
;
2344 /* Initialise the text display area */
2345 GetTextMetricsA(pDIStruct
->hDC
, &tm
);
2346 rectText
.left
= rectIcon
.right
;
2348 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
2349 rectText
.right
= pDIStruct
->rcItem
.right
+ XTEXTOFFSET
;
2351 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
2353 /* Draw the icon from the image list */
2354 ImageList_Draw(ilItemImage
,
2361 /* Draw the associated text */
2362 if(sfi
.szDisplayName
)
2363 TextOutA(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,strlen(sfi
.szDisplayName
));
2369 /***********************************************************************
2370 * FILEDLG95_LOOKIN_OnCommand
2372 * LookIn combo box WM_COMMAND message handler
2373 * If the function succeeds, the return value is nonzero.
2375 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2377 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2379 TRACE("%p\n", fodInfos
);
2385 LPSFOLDER tmpFolder
;
2388 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
2390 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
2395 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2396 tmpFolder
->pidlItem
,
2408 /***********************************************************************
2409 * FILEDLG95_LOOKIN_AddItem
2411 * Adds an absolute pidl item to the lookin combo box
2412 * returns the index of the inserted item
2414 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
2416 LPITEMIDLIST pidlNext
;
2419 LookInInfos
*liInfos
;
2421 TRACE("%08x\n", iInsertId
);
2426 if(!(liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
)))
2429 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
2430 tmpFolder
->m_iIndent
= 0;
2432 /* Calculate the indentation of the item in the lookin*/
2434 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
2436 tmpFolder
->m_iIndent
++;
2439 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
2441 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
2442 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
2444 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
2445 SHGetFileInfoA((LPSTR
)pidl
,
2449 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
2450 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
2452 TRACE("-- Add %s attr=%08lx\n", sfi
.szDisplayName
, sfi
.dwAttributes
);
2454 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
2458 TRACE("-- Add %s at %u\n", sfi
.szDisplayName
, tmpFolder
->m_iIndent
);
2460 /* Add the item at the end of the list */
2463 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
2465 /* Insert the item at the iInsertId position*/
2468 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
2471 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
2475 COMDLG32_SHFree( tmpFolder
->pidlItem
);
2476 MemFree( tmpFolder
);
2481 /***********************************************************************
2482 * FILEDLG95_LOOKIN_InsertItemAfterParent
2484 * Insert an item below its parent
2486 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
2489 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
2494 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
2498 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
2501 /* Free pidlParent memory */
2502 COMDLG32_SHFree((LPVOID
)pidlParent
);
2504 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
2507 /***********************************************************************
2508 * FILEDLG95_LOOKIN_SelectItem
2510 * Adds an absolute pidl item to the lookin combo box
2511 * returns the index of the inserted item
2513 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
2516 LookInInfos
*liInfos
;
2520 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
2522 liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
);
2526 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
2527 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
2532 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
2533 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
2537 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
2539 if(iRemovedItem
< iItemPos
)
2544 CBSetCurSel(hwnd
,iItemPos
);
2545 liInfos
->uSelectedItem
= iItemPos
;
2551 /***********************************************************************
2552 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2554 * Remove the item with an expansion level over iExpansionLevel
2556 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
2560 LookInInfos
*liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
);
2564 if(liInfos
->iMaxIndentation
<= 2)
2567 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
2569 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
2570 COMDLG32_SHFree(tmpFolder
->pidlItem
);
2572 CBDeleteString(hwnd
,iItemPos
);
2573 liInfos
->iMaxIndentation
--;
2581 /***********************************************************************
2582 * FILEDLG95_LOOKIN_SearchItem
2584 * Search for pidl in the lookin combo box
2585 * returns the index of the found item
2587 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
2590 int iCount
= CBGetCount(hwnd
);
2592 TRACE("0x%08x 0x%x\n",searchArg
, iSearchMethod
);
2594 if (iCount
!= CB_ERR
)
2598 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
2600 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
2602 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
2610 /***********************************************************************
2611 * FILEDLG95_LOOKIN_Clean
2613 * Clean the memory used by the lookin combo box
2615 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
2617 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2619 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
2623 /* Delete each string of the combo and their associated data */
2624 if (iCount
!= CB_ERR
)
2626 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
2628 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
2629 COMDLG32_SHFree(tmpFolder
->pidlItem
);
2631 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
2635 /* LookInInfos structure */
2636 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
2639 /***********************************************************************
2640 * FILEDLG95_FILENAME_FillFromSelection
2642 * fills the edit box from the cached DataObject
2644 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
2646 FileOpenDlgInfos
*fodInfos
;
2648 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nLength
= 0;
2649 char lpstrTemp
[MAX_PATH
];
2650 LPSTR lpstrAllFile
= NULL
, lpstrCurrFile
= NULL
;
2653 fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2655 /* Count how many files we have */
2656 nFileSelected
= GetNumSelected( fodInfos
->Shell
.FOIDataObject
);
2658 /* calculate the string length, count files */
2659 if (nFileSelected
>= 1)
2661 nLength
+= 3; /* first and last quotes, trailing \0 */
2662 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
2664 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
2668 /* get the total length of the selected file names*/
2669 lpstrTemp
[0] = '\0';
2670 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
2672 if ( ! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
) ) /* Ignore folders */
2674 nLength
+= strlen( lpstrTemp
) + 3;
2677 COMDLG32_SHFree( pidl
);
2682 /* allocate the buffer */
2683 if (nFiles
<= 1) nLength
= MAX_PATH
;
2684 lpstrAllFile
= (LPSTR
)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nLength
);
2685 lpstrAllFile
[0] = '\0';
2687 /* Generate the string for the edit control */
2690 lpstrCurrFile
= lpstrAllFile
;
2691 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
2693 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
2697 /* get the file name */
2698 lpstrTemp
[0] = '\0';
2699 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
2701 if (! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
)) /* Ignore folders */
2705 *lpstrCurrFile
++ = '\"';
2706 strcpy( lpstrCurrFile
, lpstrTemp
);
2707 lpstrCurrFile
+= strlen( lpstrTemp
);
2708 strcpy( lpstrCurrFile
, "\" " );
2713 strcpy( lpstrAllFile
, lpstrTemp
);
2716 COMDLG32_SHFree( (LPVOID
) pidl
);
2719 SetWindowTextA( fodInfos
->DlgInfos
.hwndFileName
, lpstrAllFile
);
2721 HeapFree(GetProcessHeap(),0, lpstrAllFile
);
2725 /* copied from shell32 to avoid linking to it */
2726 static HRESULT
COMDLG32_StrRetToStrNA (LPVOID dest
, DWORD len
, LPSTRRET src
, LPITEMIDLIST pidl
)
2731 WideCharToMultiByte(CP_ACP
, 0, src
->u
.pOleStr
, -1, (LPSTR
)dest
, len
, NULL
, NULL
);
2732 COMDLG32_SHFree(src
->u
.pOleStr
);
2736 lstrcpynA((LPSTR
)dest
, src
->u
.cStr
, len
);
2740 lstrcpynA((LPSTR
)dest
, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, len
);
2744 FIXME("unknown type!\n");
2747 *(LPSTR
)dest
= '\0';
2754 /***********************************************************************
2755 * FILEDLG95_FILENAME_GetFileNames
2757 * copies the filenames to a 0-delimited string list (A\0B\0C\0\0)
2759 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
2761 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2762 UINT nStrCharCount
= 0; /* index in src buffer */
2763 UINT nFileIndex
= 0; /* index in dest buffer */
2764 UINT nFileCount
= 0; /* number of files */
2765 UINT nStrLen
= 0; /* length of string in edit control */
2766 LPWSTR lpstrEdit
; /* buffer for string from edit control */
2770 /* get the filenames from the edit control */
2771 nStrLen
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0);
2772 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
2773 GetDlgItemTextW(hwnd
, IDC_FILENAME
, lpstrEdit
, nStrLen
+1);
2775 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
2777 /* we might get single filename without any '"',
2778 * so we need nStrLen + terminating \0 + end-of-list \0 */
2779 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
2782 /* build 0-delimited file list from filenames */
2783 while ( nStrCharCount
<= nStrLen
)
2785 if ( lpstrEdit
[nStrCharCount
]=='"' )
2788 while ((lpstrEdit
[nStrCharCount
]!='"') && (nStrCharCount
<= nStrLen
))
2790 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
2794 (*lpstrFileList
)[nFileIndex
++] = '\0';
2801 /* single, unquoted string */
2802 if ((nStrLen
> 0) && (*sizeUsed
== 0) )
2804 strcpyW(*lpstrFileList
, lpstrEdit
);
2805 nFileIndex
= strlenW(lpstrEdit
) + 1;
2806 (*sizeUsed
) = nFileIndex
;
2811 (*lpstrFileList
)[nFileIndex
] = '\0';
2818 #define SETDefFormatEtc(fe,cf,med) \
2820 (fe).cfFormat = cf;\
2821 (fe).dwAspect = DVASPECT_CONTENT; \
2828 * DATAOBJECT Helper functions
2831 /***********************************************************************
2832 * COMCTL32_ReleaseStgMedium
2834 * like ReleaseStgMedium from ole32
2836 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
2838 if(medium
.pUnkForRelease
)
2840 IUnknown_Release(medium
.pUnkForRelease
);
2844 GlobalUnlock(medium
.u
.hGlobal
);
2845 GlobalFree(medium
.u
.hGlobal
);
2849 /***********************************************************************
2850 * GetPidlFromDataObject
2852 * Return pidl(s) by number from the cached DataObject
2854 * nPidlIndex=0 gets the fully qualified root path
2856 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
2860 FORMATETC formatetc
;
2861 LPITEMIDLIST pidl
= NULL
;
2863 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
2865 /* Set the FORMATETC structure*/
2866 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
2868 /* Get the pidls from IDataObject */
2869 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
2871 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
2872 if(nPidlIndex
<= cida
->cidl
)
2874 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
2876 COMCTL32_ReleaseStgMedium(medium
);
2881 /***********************************************************************
2884 * Return the number of selected items in the DataObject.
2887 UINT
GetNumSelected( IDataObject
*doSelected
)
2891 FORMATETC formatetc
;
2893 TRACE("sv=%p\n", doSelected
);
2895 if (!doSelected
) return 0;
2897 /* Set the FORMATETC structure*/
2898 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
2900 /* Get the pidls from IDataObject */
2901 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
2903 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
2904 retVal
= cida
->cidl
;
2905 COMCTL32_ReleaseStgMedium(medium
);
2915 /***********************************************************************
2918 * Get the pidl's display name (relative to folder) and
2919 * put it in lpstrFileName.
2921 * Return NOERROR on success,
2925 HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPSTR lpstrFileName
)
2930 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
2935 SHGetDesktopFolder(&lpsf
);
2936 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
2937 IShellFolder_Release(lpsf
);
2941 /* Get the display name of the pidl relative to the folder */
2942 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
2944 return COMDLG32_StrRetToStrNA(lpstrFileName
, MAX_PATH
, &str
, pidl
);
2949 /***********************************************************************
2950 * GetShellFolderFromPidl
2952 * pidlRel is the item pidl relative
2953 * Return the IShellFolder of the absolute pidl
2955 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
2957 IShellFolder
*psf
= NULL
,*psfParent
;
2959 TRACE("%p\n", pidlAbs
);
2961 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
2964 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
2966 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
2968 IShellFolder_Release(psfParent
);
2972 /* return the desktop */
2978 /***********************************************************************
2981 * Return the LPITEMIDLIST to the parent of the pidl in the list
2983 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
2985 LPITEMIDLIST pidlParent
;
2987 TRACE("%p\n", pidl
);
2989 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
2990 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
2995 /***********************************************************************
2998 * returns the pidl of the file name relative to folder
2999 * NULL if an error occurred
3001 LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3003 LPITEMIDLIST pidl
= NULL
;
3006 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3008 if(!lpcstrFileName
) return NULL
;
3009 if(!*lpcstrFileName
) return NULL
;
3013 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3014 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3015 IShellFolder_Release(lpsf
);
3020 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3027 BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPITEMIDLIST pidl
)
3029 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3032 TRACE("%p, %p\n", psf
, pidl
);
3034 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3036 TRACE("-- 0x%08lx 0x%08lx\n", uAttr
, ret
);
3037 /* see documentation shell 4.1*/
3038 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3041 /***********************************************************************
3042 * BrowseSelectedFolder
3044 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3046 BOOL bBrowseSelFolder
= FALSE
;
3047 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
3051 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3053 LPITEMIDLIST pidlSelection
;
3055 /* get the file selected */
3056 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
3057 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
3059 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
3060 pidlSelection
, SBSP_RELATIVE
) ) )
3062 WCHAR notexist
[] = {'P','a','t','h',' ','d','o','e','s',
3063 ' ','n','o','t',' ','e','x','i','s','t',0};
3064 MessageBoxW( hwnd
, notexist
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
3067 bBrowseSelFolder
= TRUE
;
3069 COMDLG32_SHFree( pidlSelection
);
3072 return bBrowseSelFolder
;
3076 * Memory allocation methods */
3077 static void *MemAlloc(UINT size
)
3079 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
3082 static void MemFree(void *mem
)
3086 HeapFree(GetProcessHeap(),0,mem
);