2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * FIXME: lpstrCustomFilter not handeled
6 * FIXME: if the size of lpstrFile (nMaxFile) is to small the first
7 * two bytes of lpstrFile should contain the needed size
9 * FIXME: algorithm for selecting the initial directory is to simple
11 * FIXME: add to recent docs
13 * FIXME: flags not implemented: OFN_CREATEPROMPT, OFN_DONTADDTORECENT,
14 * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING, OFN_EXTENSIONDIFFERENT,
15 * OFN_NOCHANGEDIR, OFN_NODEREFERENCELINKS, OFN_READONLYRETURN,
16 * OFN_NOTESTFILECREATE, OFN_OVERWRITEPROMPT, OFN_USEMONIKERS
18 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
34 #include "debugtools.h"
39 #include "filedlgbrowser.h"
41 #include "wine/obj_contextmenu.h"
43 DEFAULT_DEBUG_CHANNEL(commdlg
);
45 /***********************************************************************
46 * Data structure and global variables
48 typedef struct SFolder
50 int m_iImageIndex
; /* Index of picture in image list */
52 int m_iIndent
; /* Indentation index */
53 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
57 typedef struct tagLookInInfo
64 /***********************************************************************
65 * Defines and global variables
68 /* Draw item constant */
76 /* SearchItem methods */
79 #define ITEM_NOTFOUND -1
81 /* Undefined windows message sent by CreateViewObject*/
82 #define WM_GETISHELLBROWSER WM_USER+7
85 * Those macros exist in windowsx.h. However, you can't really use them since
86 * they rely on the UNICODE defines and can't be use inside Wine itself.
89 /* Combo box macros */
90 #define CBAddString(hwnd,str) \
91 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
93 #define CBInsertString(hwnd,str,pos) \
94 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
96 #define CBDeleteString(hwnd,pos) \
97 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
99 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
100 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
102 #define CBGetItemDataPtr(hwnd,iItemId) \
103 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
105 #define CBGetLBText(hwnd,iItemId,str) \
106 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
108 #define CBGetCurSel(hwnd) \
109 SendMessageA(hwnd,CB_GETCURSEL,0,0);
111 #define CBSetCurSel(hwnd,pos) \
112 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
114 #define CBGetCount(hwnd) \
115 SendMessageA(hwnd,CB_GETCOUNT,0,0);
116 #define CBShowDropDown(hwnd,show) \
117 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
118 #define CBSetItemHeight(hwnd,index,height) \
119 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
122 const char *FileOpenDlgInfosStr
= "FileOpenDlgInfos"; /* windows property description string */
123 const char *LookInInfosStr
= "LookInInfos"; /* LOOKIN combo box property */
125 static const char defaultFilter
[] = "*.*";
127 /***********************************************************************
131 /* Internal functions used by the dialog */
132 static LRESULT
FILEDLG95_OnWMInitDialog(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
133 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
134 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
135 BOOL
FILEDLG95_OnOpen(HWND hwnd
);
136 static LRESULT
FILEDLG95_InitUI(HWND hwnd
);
137 static void FILEDLG95_Clean(HWND hwnd
);
139 /* Functions used by the shell object */
140 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
141 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
142 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
143 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
145 /* Functions used by the filetype combo box */
146 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
147 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
148 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCSTR lpstrExt
);
149 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
151 /* Functions used by the Look In combo box */
152 static HRESULT
FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
153 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
154 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
155 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
156 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
157 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
158 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
159 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
160 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
162 /* Miscellaneous tool functions */
163 HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPSTR lpstrFileName
);
164 HRESULT
GetFileName(HWND hwnd
, LPITEMIDLIST pidl
, LPSTR lpstrFileName
);
165 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
166 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
167 LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPCSTR lpcstrFileName
);
169 /* Shell memory allocation */
170 static void *MemAlloc(UINT size
);
171 static void MemFree(void *mem
);
173 BOOL WINAPI
GetFileName95(FileOpenDlgInfos
*fodInfos
);
174 HRESULT WINAPI
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
175 HRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
);
176 HRESULT
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
177 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
178 static BOOL
BrowseSelectedFolder(HWND hwnd
);
180 /***********************************************************************
183 * Creates an Open common dialog box that lets the user select
184 * the drive, directory, and the name of a file or set of files to open.
186 * IN : The FileOpenDlgInfos structure associated with the dialog
187 * OUT : TRUE on success
188 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
190 BOOL WINAPI
GetFileName95(FileOpenDlgInfos
*fodInfos
)
198 /* Create the dialog from a template */
200 if(!(hRes
= FindResourceA(COMMDLG_hInstance32
,MAKEINTRESOURCEA(NEWFILEOPENORD
),RT_DIALOGA
)))
202 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
205 if (!(hDlgTmpl
= LoadResource(COMMDLG_hInstance32
, hRes
)) ||
206 !(template = LockResource( hDlgTmpl
)))
208 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
211 lRes
= DialogBoxIndirectParamA(COMMDLG_hInstance32
,
212 (LPDLGTEMPLATEA
) template,
213 fodInfos
->ofnInfos
->hwndOwner
,
214 (DLGPROC
) FileOpenDlgProc95
,
217 /* Unable to create the dialog*/
224 /***********************************************************************
227 * Call GetFileName95 with this structure and clean the memory.
229 * IN : The OPENFILENAMEA initialisation structure passed to
230 * GetOpenFileNameA win api function (see filedlg.c)
232 BOOL WINAPI
GetFileDialog95A(LPOPENFILENAMEA ofn
,UINT iDlgType
)
236 FileOpenDlgInfos
*fodInfos
;
238 LPCSTR lpstrInitialDir
= NULL
;
241 /* Initialise FileOpenDlgInfos structure*/
242 fodInfos
= (FileOpenDlgInfos
*)MemAlloc(sizeof(FileOpenDlgInfos
));
243 ZeroMemory(fodInfos
, sizeof(FileOpenDlgInfos
));
245 /* Pass in the original ofn */
246 fodInfos
->ofnInfos
= ofn
;
248 /* Save original hInstance value */
249 hInstance
= ofn
->hInstance
;
250 fodInfos
->ofnInfos
->hInstance
= MapHModuleLS(ofn
->hInstance
);
252 dwFlags
= ofn
->Flags
;
253 ofn
->Flags
= ofn
->Flags
|OFN_WINE
;
255 /* Replace the NULL lpstrInitialDir by the current folder */
256 if(!ofn
->lpstrInitialDir
)
258 lpstrInitialDir
= ofn
->lpstrInitialDir
;
259 ofn
->lpstrInitialDir
= MemAlloc(MAX_PATH
);
260 GetCurrentDirectoryA(MAX_PATH
,(LPSTR
)ofn
->lpstrInitialDir
);
263 /* Initialise the dialog property */
264 fodInfos
->DlgInfos
.dwDlgProp
= 0;
265 fodInfos
->DlgInfos
.hwndCustomDlg
= (HWND
)NULL
;
270 ret
= GetFileName95(fodInfos
);
273 fodInfos
->DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
274 ret
= GetFileName95(fodInfos
);
282 MemFree((LPVOID
)(ofn
->lpstrInitialDir
));
283 ofn
->lpstrInitialDir
= lpstrInitialDir
;
286 ofn
->Flags
= dwFlags
;
287 ofn
->hInstance
= hInstance
;
288 MemFree((LPVOID
)(fodInfos
));
292 /***********************************************************************
295 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
296 * Call GetFileName95 with this structure and clean the memory.
298 * IN : The OPENFILENAMEW initialisation structure passed to
299 * GetOpenFileNameW win api function (see filedlg.c)
302 * some more strings are needing to be convertet AtoW
304 BOOL WINAPI
GetFileDialog95W(LPOPENFILENAMEW ofn
,UINT iDlgType
)
307 FileOpenDlgInfos
*fodInfos
;
309 LPCSTR lpstrFilter
= NULL
;
310 LPSTR lpstrCustomFilter
= NULL
;
311 LPWSTR lpstrFile
= NULL
;
314 /* Initialise FileOpenDlgInfos structure*/
315 fodInfos
= (FileOpenDlgInfos
*)MemAlloc(sizeof(FileOpenDlgInfos
));
316 ZeroMemory(fodInfos
, sizeof(FileOpenDlgInfos
));
318 /* Pass in the original ofn */
319 fodInfos
->ofnInfos
= (LPOPENFILENAMEA
) ofn
;
322 hInstance
= fodInfos
->ofnInfos
->hInstance
;
323 fodInfos
->ofnInfos
->hInstance
= MapHModuleLS(ofn
->hInstance
);
325 /* Save lpstrFilter */
326 if (ofn
->lpstrFilter
)
332 lpstrFilter
= fodInfos
->ofnInfos
->lpstrFilter
;
334 /* filter is a list... title\0ext\0......\0\0 */
335 s
= (LPWSTR
)ofn
->lpstrFilter
;
340 n
= s
- ofn
->lpstrFilter
; /* already divides by 2. ptr magic */
341 x
= y
= (LPSTR
)MemAlloc(n
);
342 s
= (LPWSTR
)ofn
->lpstrFilter
;
349 fodInfos
->ofnInfos
->lpstrFilter
= (LPSTR
)y
;
351 /* Save lpstrCustomFilter */
352 if (ofn
->lpstrCustomFilter
)
358 lpstrCustomFilter
= fodInfos
->ofnInfos
->lpstrCustomFilter
;
359 /* filter is a list... title\0ext\0......\0\0 */
360 s
= (LPWSTR
)ofn
->lpstrCustomFilter
;
364 n
= s
- ofn
->lpstrCustomFilter
;
365 x
= y
= (LPSTR
)MemAlloc(n
);
366 s
= (LPWSTR
)ofn
->lpstrCustomFilter
;
373 fodInfos
->ofnInfos
->lpstrCustomFilter
= (LPSTR
)y
;
377 dwFlags
= fodInfos
->ofnInfos
->Flags
;
378 fodInfos
->ofnInfos
->Flags
= ofn
->Flags
|OFN_WINE
|OFN_UNICODE
;
380 /* Initialise the dialog property */
381 fodInfos
->DlgInfos
.dwDlgProp
= 0;
383 /* allocate ansi filename buffer */
384 lpstrFile
= ofn
->lpstrFile
;
385 ofn
->lpstrFile
= MemAlloc(ofn
->nMaxFile
);
390 ret
= GetFileName95(fodInfos
);
393 fodInfos
->DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
394 ret
= GetFileName95(fodInfos
);
402 fodInfos
->ofnInfos
->Flags
= dwFlags
;
404 /* Restore lpstrFilter */
405 if (fodInfos
->ofnInfos
->lpstrFilter
)
407 MemFree((LPVOID
)(fodInfos
->ofnInfos
->lpstrFilter
));
408 fodInfos
->ofnInfos
->lpstrFilter
= lpstrFilter
;
410 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
412 MemFree((LPVOID
)(fodInfos
->ofnInfos
->lpstrCustomFilter
));
413 fodInfos
->ofnInfos
->lpstrCustomFilter
= lpstrCustomFilter
;
416 /* Restore hInstance */
417 fodInfos
->ofnInfos
->hInstance
= hInstance
;
418 MemFree((LPVOID
)(fodInfos
));
421 lstrcpynAtoW(lpstrFile
, (LPCSTR
)ofn
->lpstrFile
, ofn
->nMaxFile
);
422 MemFree(ofn
->lpstrFile
);
423 ofn
->lpstrFile
= lpstrFile
;
428 void ArrangeCtrlPositions( HWND hwndChildDlg
, HWND hwndParentDlg
)
431 HWND hwndChild
,hwndStc32
;
432 RECT rectParent
, rectChild
, rectCtrl
, rectStc32
, rectTemp
;
434 POINT ptParentClient
;
436 ptMoveCtl
.x
= ptMoveCtl
.y
= 0;
437 hwndStc32
=GetDlgItem(hwndChildDlg
,stc32
);
438 GetClientRect(hwndParentDlg
,&rectParent
);
439 GetClientRect(hwndChildDlg
,&rectChild
);
442 GetWindowRect(hwndStc32
,&rectStc32
);
443 MapWindowPoints(0, hwndChildDlg
,(LPPOINT
)&rectStc32
,2);
444 CopyRect(&rectTemp
,&rectStc32
);
446 SetRect(&rectStc32
,rectStc32
.left
,rectStc32
.top
,rectStc32
.left
+ (rectParent
.right
-rectParent
.left
),rectStc32
.top
+(rectParent
.bottom
-rectParent
.top
));
447 SetWindowPos(hwndStc32
,0,rectStc32
.left
,rectStc32
.top
,rectStc32
.right
-rectStc32
.left
,rectStc32
.bottom
-rectStc32
.top
,SWP_NOMOVE
|SWP_NOZORDER
| SWP_NOACTIVATE
);
449 if(rectStc32
.right
< rectTemp
.right
)
451 ptParentClient
.x
= max((rectParent
.right
-rectParent
.left
),(rectChild
.right
-rectChild
.left
));
456 ptMoveCtl
.x
= (rectStc32
.right
- rectTemp
.right
);
457 ptParentClient
.x
= max((rectParent
.right
-rectParent
.left
),((rectChild
.right
-rectChild
.left
)+rectStc32
.right
-rectTemp
.right
));
459 if(rectStc32
.bottom
< rectTemp
.bottom
)
461 ptParentClient
.y
= max((rectParent
.bottom
-rectParent
.top
),(rectChild
.bottom
-rectChild
.top
));
466 ptMoveCtl
.y
= (rectStc32
.bottom
- rectTemp
.bottom
);
467 ptParentClient
.y
= max((rectParent
.bottom
-rectParent
.top
),((rectChild
.bottom
-rectChild
.top
)+rectStc32
.bottom
-rectTemp
.bottom
));
472 if( (GetWindow(hwndChildDlg
,GW_CHILD
)) == (HWND
) NULL
)
474 SetRectEmpty(&rectTemp
);
475 ptParentClient
.x
= max((rectParent
.right
-rectParent
.left
),(rectChild
.right
-rectChild
.left
));
476 ptParentClient
.y
= (rectParent
.bottom
-rectParent
.top
) + (rectChild
.bottom
-rectChild
.top
);
477 ptMoveCtl
.y
= rectParent
.bottom
-rectParent
.top
;
480 SetRect(&rectParent
,rectParent
.left
,rectParent
.top
,rectParent
.left
+ptParentClient
.x
,rectParent
.top
+ptParentClient
.y
);
481 AdjustWindowRectEx( &rectParent
,GetWindowLongA(hwndParentDlg
,GWL_STYLE
),FALSE
,GetWindowLongA(hwndParentDlg
,GWL_EXSTYLE
));
483 SetWindowPos(hwndChildDlg
, 0, 0,0, ptParentClient
.x
,ptParentClient
.y
,
485 SetWindowPos(hwndParentDlg
, 0, rectParent
.left
,rectParent
.top
, (rectParent
.right
- rectParent
.left
),
486 (rectParent
.bottom
-rectParent
.top
),SWP_NOMOVE
| SWP_NOZORDER
);
488 hwndChild
= GetWindow(hwndChildDlg
,GW_CHILD
);
491 GetWindowRect(hwndStc32
,&rectStc32
);
492 MapWindowPoints( 0, hwndChildDlg
,(LPPOINT
)&rectStc32
,2);
495 SetRect(&rectStc32
,0,0,0,0);
501 if(hwndChild
!= hwndStc32
)
503 if (GetWindowLongA( hwndChild
, GWL_STYLE
) & WS_MAXIMIZE
)
505 GetWindowRect(hwndChild
,&rectCtrl
);
506 MapWindowPoints( 0, hwndParentDlg
,(LPPOINT
)&rectCtrl
,2);
509 Check the initial position of the controls relative to the initial
510 position and size of stc32 (before it is expanded).
512 if (rectCtrl
.left
>= rectTemp
.right
&& rectCtrl
.top
>= rectTemp
.bottom
)
514 rectCtrl
.left
+= ptMoveCtl
.x
;
515 rectCtrl
.top
+= ptMoveCtl
.y
;
517 else if (rectCtrl
.left
>= rectTemp
.right
)
518 rectCtrl
.left
+= ptMoveCtl
.x
;
519 else if (rectCtrl
.top
>= rectTemp
.bottom
)
520 rectCtrl
.top
+= ptMoveCtl
.y
;
522 SetWindowPos( hwndChild
, 0, rectCtrl
.left
, rectCtrl
.top
,
523 rectCtrl
.right
-rectCtrl
.left
,rectCtrl
.bottom
-rectCtrl
.top
,
524 SWP_NOSIZE
| SWP_NOZORDER
);
527 while ((hwndChild
=GetWindow( hwndChild
, GW_HWNDNEXT
)) != (HWND
)NULL
);
529 hwndChild
= GetWindow(hwndParentDlg
,GW_CHILD
);
533 GetWindowRect(hwndStc32
,&rectStc32
);
534 MapWindowPoints( 0, hwndChildDlg
,(LPPOINT
)&rectStc32
,2);
535 ptMoveCtl
.x
= rectStc32
.left
- 0;
536 ptMoveCtl
.y
= rectStc32
.top
- 0;
541 if(hwndChild
!= hwndChildDlg
)
544 if (GetWindowLongA( hwndChild
, GWL_STYLE
) & WS_MAXIMIZE
)
546 GetWindowRect(hwndChild
,&rectCtrl
);
547 MapWindowPoints( 0, hwndParentDlg
,(LPPOINT
)&rectCtrl
,2);
549 rectCtrl
.left
+= ptMoveCtl
.x
;
550 rectCtrl
.top
+= ptMoveCtl
.y
;
552 SetWindowPos( hwndChild
, 0, rectCtrl
.left
, rectCtrl
.top
,
553 rectCtrl
.right
-rectCtrl
.left
,rectCtrl
.bottom
-rectCtrl
.top
,
554 SWP_NOSIZE
|SWP_NOZORDER
);
557 while ((hwndChild
=GetWindow( hwndChild
, GW_HWNDNEXT
)) != (HWND
)NULL
);
564 HRESULT WINAPI
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
566 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(GetParent(hwnd
),FileOpenDlgInfosStr
);
571 fodInfos
= (FileOpenDlgInfos
*)lParam
;
572 lParam
= (LPARAM
) fodInfos
->ofnInfos
;
573 ArrangeCtrlPositions(hwnd
,GetParent(hwnd
));
574 if(fodInfos
&& (fodInfos
->ofnInfos
->Flags
& OFN_ENABLEHOOK
) && fodInfos
->ofnInfos
->lpfnHook
)
575 return CallWindowProcA((WNDPROC
)fodInfos
->ofnInfos
->lpfnHook
,hwnd
,uMsg
,wParam
,lParam
);
579 if(fodInfos
&& (fodInfos
->ofnInfos
->Flags
& OFN_ENABLEHOOK
) && fodInfos
->ofnInfos
->lpfnHook
)
580 return CallWindowProcA((WNDPROC
)fodInfos
->ofnInfos
->lpfnHook
,hwnd
,uMsg
,wParam
,lParam
);
581 return DefWindowProcA(hwnd
,uMsg
,wParam
,lParam
);
584 HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
,HWND hwnd
)
590 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATE
|| fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
592 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
594 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
596 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
603 if (!(hRes
= FindResourceA(MapHModuleSL(fodInfos
->ofnInfos
->hInstance
),
604 (fodInfos
->ofnInfos
->lpTemplateName
), RT_DIALOGA
)))
606 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
609 if (!(hDlgTmpl
= LoadResource( MapHModuleSL(fodInfos
->ofnInfos
->hInstance
),
611 !(template = LockResource( hDlgTmpl
)))
613 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
618 hChildDlg
= CreateDialogIndirectParamA(fodInfos
->ofnInfos
->hInstance
,template,hwnd
,(DLGPROC
)FileOpenDlgProcUserTemplate
,(LPARAM
)fodInfos
);
621 ShowWindow(hChildDlg
,SW_SHOW
);
625 else if(fodInfos
->ofnInfos
->Flags
& OFN_ENABLEHOOK
&& fodInfos
->ofnInfos
->lpfnHook
)
629 GetClientRect(hwnd
,&rectHwnd
);
630 tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
;
631 tmplate
.dwExtendedStyle
= 0;
635 tmplate
.cx
= rectHwnd
.right
-rectHwnd
.left
;
636 tmplate
.cy
= rectHwnd
.bottom
-rectHwnd
.top
;
638 return CreateDialogIndirectParamA(fodInfos
->ofnInfos
->hInstance
,&tmplate
,hwnd
,(DLGPROC
)FileOpenDlgProcUserTemplate
,(LPARAM
)fodInfos
);
643 /***********************************************************************
644 * SendCustomDlgNotificationMessage
646 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
649 HRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
651 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwndParentDlg
,FileOpenDlgInfosStr
);
654 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
657 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
658 ofnNotify
.hdr
.idFrom
=0;
659 ofnNotify
.hdr
.code
= uCode
;
660 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
661 return SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
666 /***********************************************************************
667 * FILEDLG95_HandleCustomDialogMessages
669 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
671 HRESULT
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
675 char lpstrPath
[MAX_PATH
];
676 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
677 if(!fodInfos
) return -1;
681 case CDM_GETFILEPATH
:
682 GetDlgItemTextA(hwnd
,IDC_FILENAME
,lpstrPath
, sizeof(lpstrPath
));
683 lpstrFileSpec
= (LPSTR
)COMDLG32_PathFindFileNameA(lpstrPath
);
684 if (lpstrFileSpec
==lpstrPath
)
686 char lpstrCurrentDir
[MAX_PATH
];
687 /* Prepend the current path */
688 COMDLG32_SHGetPathFromIDListA(fodInfos
->ShellInfos
.pidlAbsCurrent
,lpstrCurrentDir
);
689 if ((LPSTR
)lParam
!=NULL
)
690 wsnprintfA((LPSTR
)lParam
,(int)wParam
,"%s\\%s",lpstrCurrentDir
,lpstrPath
);
691 reqSize
=strlen(lpstrCurrentDir
)+1+strlen(lpstrPath
)+1;
695 lstrcpynA((LPSTR
)lParam
,(LPSTR
)lpstrPath
,(int)wParam
);
696 reqSize
=strlen(lpstrPath
);
698 /* return the required buffer size */
701 case CDM_GETFOLDERPATH
:
702 COMDLG32_SHGetPathFromIDListA(fodInfos
->ShellInfos
.pidlAbsCurrent
,lpstrPath
);
703 if ((LPSTR
)lParam
!=NULL
)
704 lstrcpynA((LPSTR
)lParam
,lpstrPath
,(int)wParam
);
705 return strlen(lpstrPath
);
708 reqSize
=GetDlgItemTextA(hwnd
,IDC_FILENAME
,lpstrPath
, sizeof(lpstrPath
));
709 lpstrFileSpec
= (LPSTR
)COMDLG32_PathFindFileNameA(lpstrPath
);
710 if ((LPSTR
)lParam
!=NULL
)
711 lstrcpynA((LPSTR
)lParam
, lpstrFileSpec
, (int)wParam
);
712 return strlen(lpstrFileSpec
);
714 case CDM_SETCONTROLTEXT
:
716 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
719 case CDM_HIDECONTROL
:
721 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
727 /***********************************************************************
730 * File open dialog procedure
732 HRESULT WINAPI
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
737 /* Adds the FileOpenDlgInfos in the property list of the dialog
738 so it will be easily accessible through a GetPropA(...) */
739 SetPropA(hwnd
, FileOpenDlgInfosStr
, (HANDLE
) lParam
);
741 FILEDLG95_OnWMInitDialog(hwnd
, wParam
, lParam
);
742 ((FileOpenDlgInfos
*)lParam
)->DlgInfos
.hwndCustomDlg
=
743 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
,hwnd
);
744 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
747 return FILEDLG95_OnWMCommand(hwnd
, wParam
, lParam
);
750 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
753 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
759 case WM_GETISHELLBROWSER
:
760 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
763 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
768 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
771 /* set up the button tooltips strings */
772 if(TTN_GETDISPINFOA
== lpnmh
->code
)
774 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
775 switch(lpnmh
->idFrom
)
777 /* Up folder button */
778 case FCIDM_TB_UPFOLDER
:
779 stringId
= IDS_UPFOLDER
;
781 /* New folder button */
782 case FCIDM_TB_NEWFOLDER
:
783 stringId
= IDS_NEWFOLDER
;
785 /* List option button */
786 case FCIDM_TB_SMALLICON
:
787 stringId
= IDS_LISTVIEW
;
789 /* Details option button */
790 case FCIDM_TB_REPORTVIEW
:
791 stringId
= IDS_REPORTVIEW
;
794 lpdi
->hinst
= COMMDLG_hInstance32
;
795 lpdi
->lpszText
= (LPSTR
) stringId
;
800 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
801 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
806 /***********************************************************************
807 * FILEDLG95_OnWMInitDialog
809 * WM_INITDIALOG message handler
811 static LRESULT
FILEDLG95_OnWMInitDialog(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
813 LPITEMIDLIST pidlItemId
;
814 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
818 /* Initialise shell objects */
819 FILEDLG95_SHELL_Init(hwnd
);
821 /* Initialise dialog UI */
822 FILEDLG95_InitUI(hwnd
);
824 /* Initialize the Look In combo box*/
825 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
827 /* Initialize the filter combo box */
828 FILEDLG95_FILETYPE_Init(hwnd
);
830 /* Get the initial directory pidl */
832 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->ofnInfos
->lpstrInitialDir
)))
836 GetCurrentDirectoryA(MAX_PATH
,path
);
837 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,
842 /* Browse to the initial directory */
843 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
845 /* Free pidlItem memory */
846 COMDLG32_SHFree(pidlItemId
);
850 /***********************************************************************
853 * Regroups all the cleaning functions of the filedlg
855 void FILEDLG95_Clean(HWND hwnd
)
857 FILEDLG95_FILETYPE_Clean(hwnd
);
858 FILEDLG95_LOOKIN_Clean(hwnd
);
859 FILEDLG95_SHELL_Clean(hwnd
);
861 /***********************************************************************
862 * FILEDLG95_OnWMCommand
864 * WM_COMMAND message handler
866 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
868 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
869 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
870 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
876 if(FILEDLG95_OnOpen(hwnd
))
877 SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
881 FILEDLG95_Clean(hwnd
);
882 EndDialog(hwnd
, FALSE
);
884 /* Filetype combo box */
886 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
888 /* LookIn combo box */
890 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
893 /* --- toolbar --- */
894 /* Up folder button */
895 case FCIDM_TB_UPFOLDER
:
896 FILEDLG95_SHELL_UpFolder(hwnd
);
898 /* New folder button */
899 case FCIDM_TB_NEWFOLDER
:
900 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDER
);
902 /* List option button */
903 case FCIDM_TB_SMALLICON
:
904 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLIST
);
906 /* Details option button */
907 case FCIDM_TB_REPORTVIEW
:
908 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILS
);
915 /* Do not use the listview selection anymore */
916 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
920 /***********************************************************************
921 * FILEDLG95_OnWMGetIShellBrowser
923 * WM_GETISHELLBROWSER message handler
925 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
928 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
932 SetWindowLongA(hwnd
,DWL_MSGRESULT
,(LONG
)fodInfos
->Shell
.FOIShellBrowser
);
938 /***********************************************************************
942 static LRESULT
FILEDLG95_InitUI(HWND hwnd
)
945 {{VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, TBSTYLE_BUTTON
, {0, 0}, 0, 0 },
946 {0, 0, TBSTATE_ENABLED
, TBSTYLE_SEP
, {0, 0}, 0, 0 },
947 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, TBSTYLE_BUTTON
, {0, 0}, 0, 0 },
948 {0, 0, TBSTATE_ENABLED
, TBSTYLE_SEP
, {0, 0}, 0, 0 },
949 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, TBSTYLE_BUTTON
, {0, 0}, 0, 0 },
950 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, TBSTYLE_BUTTON
, {0, 0}, 0, 0 },
952 TBADDBITMAP tba
= { HINST_COMMCTRL
, IDB_VIEW_SMALL_COLOR
};
955 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
957 TRACE("%p\n", fodInfos
);
959 /* Get the hwnd of the controls */
960 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem(hwnd
,IDC_FILENAME
);
961 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
962 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
964 /* construct the toolbar */
965 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
966 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
968 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, (LPSTR
) NULL
,
969 WS_CHILD
| WS_GROUP
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
971 hwnd
, (HMENU
) IDC_TOOLBAR
, COMMDLG_hInstance32
, NULL
);
973 SetWindowPos(fodInfos
->DlgInfos
.hwndTB
, 0,
974 rectTB
.left
,rectTB
.top
, rectTB
.right
-rectTB
.left
, rectTB
.bottom
-rectTB
.top
,
975 SWP_SHOWWINDOW
| SWP_NOACTIVATE
| SWP_NOZORDER
);
977 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, (WPARAM
) sizeof(TBBUTTON
), 0);
979 /* fixme: use TB_LOADIMAGES when implemented */
980 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
981 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, (WPARAM
) 12, (LPARAM
) &tba
);
983 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSA
, (WPARAM
) 6,(LPARAM
) &tbb
);
984 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
986 /* Set the window text with the text specified in the OPENFILENAME structure */
987 if(fodInfos
->ofnInfos
->lpstrTitle
)
989 SetWindowTextA(hwnd
,fodInfos
->ofnInfos
->lpstrTitle
);
991 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
993 SetWindowTextA(hwnd
,"Save");
996 /* Initialise the file name edit control */
997 if(fodInfos
->ofnInfos
->lpstrFile
)
999 SetDlgItemTextA(hwnd
,IDC_FILENAME
,fodInfos
->ofnInfos
->lpstrFile
);
1002 /* Must the open as read only check box be checked ?*/
1003 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1005 SendDlgItemMessageA(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,(WPARAM
)TRUE
,0);
1008 /* Must the open as read only check box be hid ?*/
1009 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1011 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1014 /* Must the help button be hid ?*/
1015 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1017 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1020 /* Resize the height, if open as read only checkbox ad help button
1022 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1023 (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
)) )
1025 RECT rectDlg
, rectHelp
, rectCancel
;
1026 GetWindowRect(hwnd
, &rectDlg
);
1027 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1028 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1029 /* subtract the height of the help button plus the space between
1030 the help button and the cancel button to the height of the dialog */
1031 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1032 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1033 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1036 /* change Open to Save FIXME: use resources */
1037 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1039 SetDlgItemTextA(hwnd
,IDOK
,"&Save");
1040 SetDlgItemTextA(hwnd
,IDC_LOOKINSTATIC
,"Save &in");
1045 /***********************************************************************
1046 * FILEDLG95_OnOpenMultipleFiles
1048 * Handles the opening of multiple files.
1051 * check destination buffer size
1053 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1055 CHAR lpstrPathSpec
[MAX_PATH
] = "";
1057 UINT nCount
, nSizePath
;
1058 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1062 lpstrFile
= fodInfos
->ofnInfos
->lpstrFile
;
1063 lpstrFile
[0] = '\0';
1065 COMDLG32_SHGetPathFromIDListA( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
1067 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1068 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
1070 LPSTR lpstrTemp
= lpstrFileList
;
1072 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
1076 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
1079 CHAR lpstrNotFound
[100];
1083 LoadStringA(COMMDLG_hInstance32
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
1084 LoadStringA(COMMDLG_hInstance32
, IDS_VERIFYFILE
, lpstrMsg
, 100);
1086 strcpy(tmp
, lpstrTemp
);
1088 strcat(tmp
, lpstrNotFound
);
1090 strcat(tmp
, lpstrMsg
);
1092 MessageBoxA(hwnd
, tmp
, fodInfos
->ofnInfos
->lpstrTitle
, MB_OK
| MB_ICONEXCLAMATION
);
1096 lpstrTemp
+= strlen(lpstrFileList
) + 1;
1097 COMDLG32_SHFree(pidl
);
1101 nSizePath
= lstrlenA(lpstrPathSpec
);
1102 lstrcpyA( lpstrFile
, lpstrPathSpec
);
1103 memcpy( lpstrFile
+ nSizePath
+ 1, lpstrFileList
, sizeUsed
);
1105 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
+ 1;
1106 fodInfos
->ofnInfos
->nFileExtension
= 0;
1108 /* clean and exit */
1109 FILEDLG95_Clean(hwnd
);
1110 return EndDialog(hwnd
,TRUE
);
1113 /***********************************************************************
1116 * Ok button WM_COMMAND message handler
1118 * If the function succeeds, the return value is nonzero.
1120 #define ONOPEN_BROWSE 1
1121 #define ONOPEN_OPEN 2
1122 #define ONOPEN_SEARCH 3
1123 static void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
1125 char strMsgTitle
[MAX_PATH
];
1126 char strMsgText
[MAX_PATH
];
1128 LoadStringA(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
));
1130 strMsgTitle
[0] = '\0';
1131 LoadStringA(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
));
1132 MessageBoxA(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
1135 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
1137 char * lpstrFileList
;
1138 UINT nFileCount
= 0;
1141 char lpstrPathAndFile
[MAX_PATH
];
1142 char lpstrTemp
[MAX_PATH
];
1143 LPSHELLFOLDER lpsf
= NULL
;
1145 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1148 TRACE("hwnd=0x%04x\n", hwnd
);
1150 /* get the files from the edit control */
1151 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
1153 /* try if the user selected a folder in the shellview */
1156 if (BrowseSelectedFolder(hwnd
))
1162 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
1166 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, lpstrFileList
);
1169 Step 1: Build a complete path name from the current folder and
1170 the filename or path in the edit box.
1172 - the path in the edit box is a root path
1173 (with or without drive letter)
1174 - the edit box contains ".." (or a path with ".." in it)
1177 /* Get the current directory name */
1178 if (!COMDLG32_SHGetPathFromIDListA(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathAndFile
))
1180 /* we are in a special folder, default to desktop */
1181 if(FAILED(COMDLG32_SHGetFolderPathA(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, NULL
, 0, lpstrPathAndFile
)))
1184 GetCurrentDirectoryA(MAX_PATH
, lpstrPathAndFile
);
1187 COMDLG32_PathAddBackslashA(lpstrPathAndFile
);
1189 TRACE("current directory=%s\n", lpstrPathAndFile
);
1191 /* if the user specifyed a fully qualified path use it */
1192 if(COMDLG32_PathIsRelativeA(lpstrFileList
))
1194 strcat(lpstrPathAndFile
, lpstrFileList
);
1198 /* does the path have a drive letter? */
1199 if (COMDLG32_PathGetDriveNumberA(lpstrFileList
) == -1)
1200 strcpy(lpstrPathAndFile
+2, lpstrFileList
);
1202 strcpy(lpstrPathAndFile
, lpstrFileList
);
1205 /* resolve "." and ".." */
1206 COMDLG32_PathCanonicalizeA(lpstrTemp
, lpstrPathAndFile
);
1207 strcpy(lpstrPathAndFile
, lpstrTemp
);
1208 TRACE("canon=%s\n", lpstrPathAndFile
);
1210 MemFree(lpstrFileList
);
1213 Step 2: here we have a cleaned up path
1215 We have to parse the path step by step to see if we have to browse
1216 to a folder if the path points to a directory or the last
1217 valid element is a directory.
1220 lpstrPathAndFile: cleaned up path
1223 nOpenAction
= ONOPEN_BROWSE
;
1225 /* dont apply any checks with OFN_NOVALIDATE */
1226 if(!(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1228 LPSTR lpszTemp
, lpszTemp1
;
1229 LPITEMIDLIST pidl
= NULL
;
1231 /* check for invalid chars */
1232 if(strpbrk(lpstrPathAndFile
+3, "/:<>|") != NULL
)
1234 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
1239 if (FAILED (COMDLG32_SHGetDesktopFolder(&lpsf
))) return FALSE
;
1241 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
1244 LPSHELLFOLDER lpsfChild
;
1245 WCHAR lpwstrTemp
[MAX_PATH
];
1246 DWORD dwEaten
, dwAttributes
;
1248 lpszTemp
= COMDLG32_PathFindNextComponentA(lpszTemp
);
1250 lstrcpynAtoW(lpwstrTemp
, lpszTemp1
, lpszTemp
- lpszTemp1
);
1253 lstrcpyAtoW(lpwstrTemp
, lpszTemp1
); /* last element */
1254 if(strpbrk(lpszTemp1
, "*?") != NULL
)
1256 nOpenAction
= ONOPEN_SEARCH
;
1260 lpszTemp1
= lpszTemp
;
1262 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_a(lpszTemp
), lpsf
);
1264 if(lstrlenW(lpwstrTemp
)==2) COMDLG32_PathAddBackslashW(lpwstrTemp
);
1266 dwAttributes
= SFGAO_FOLDER
;
1267 if(FAILED(IShellFolder_ParseDisplayName(lpsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
1269 if(lpszTemp
) /* is null for last path element */
1271 if(fodInfos
->ofnInfos
->Flags
& OFN_PATHMUSTEXIST
)
1273 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
1279 if(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
)
1281 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
1285 /* change to the current folder */
1286 nOpenAction
= ONOPEN_OPEN
;
1291 /* the path component is valid */
1292 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes
, pidl
);
1293 if(dwAttributes
& SFGAO_FOLDER
)
1295 if(FAILED(IShellFolder_BindToObject(lpsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
1297 ERR("bind to failed\n"); /* should not fail */
1300 IShellFolder_Release(lpsf
);
1308 /* end dialog, return value */
1309 nOpenAction
= ONOPEN_OPEN
;
1312 COMDLG32_SHFree(pidl
);
1316 if(pidl
) COMDLG32_SHFree(pidl
);
1319 /* path is valid, clean the edit box */
1320 SetDlgItemTextA(hwnd
,IDC_FILENAME
,"");
1323 Step 3: here we have a cleaned up and validated path
1326 lpsf: ShellFolder bound to the rightmost valid path component
1327 lpstrPathAndFile: cleaned up path
1328 nOpenAction: action to do
1330 TRACE("end validate sf=%p\n", lpsf
);
1334 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
1335 TRACE("ONOPEN_SEARCH %s\n", lpstrPathAndFile
);
1338 LPSTR lpszTemp
= COMDLG32_PathFindFileNameA(lpstrPathAndFile
);
1340 /* replace the current filter */
1341 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
1342 MemFree((LPVOID
)fodInfos
->ShellInfos
.lpstrCurrentFilter
);
1343 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc((strlen(lpszTemp
)+1)*sizeof(WCHAR
));
1344 lstrcpyAtoW(fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
1346 /* set the filter cb to the extension when possible */
1347 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
1348 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
1351 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
1352 TRACE("ONOPEN_BROWSE\n");
1354 IPersistFolder2
* ppf2
;
1355 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
1357 LPITEMIDLIST pidlCurrent
;
1358 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
1359 IPersistFolder2_Release(ppf2
);
1360 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
1362 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
);
1364 else if( nOpenAction
== ONOPEN_SEARCH
)
1366 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
1368 COMDLG32_SHFree(pidlCurrent
);
1373 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
1374 TRACE("ONOPEN_OPEN %s\n", lpstrPathAndFile
);
1376 /* add default extension */
1377 if (fodInfos
->ofnInfos
->lpstrDefExt
)
1378 COMDLG32_PathAddExtensionA(lpstrPathAndFile
, fodInfos
->ofnInfos
->lpstrDefExt
);
1380 /* Check that size size of the file does not exceed buffer size */
1381 if(strlen(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
)
1385 /* fill destination buffer */
1386 strcpy(fodInfos
->ofnInfos
->lpstrFile
, lpstrPathAndFile
);
1388 /* set filename offset */
1389 lpszTemp
= COMDLG32_PathFindFileNameA(lpstrPathAndFile
);
1390 fodInfos
->ofnInfos
->nFileOffset
= lpszTemp
- lpstrPathAndFile
;
1392 /* set extension offset */
1393 lpszTemp
= COMDLG32_PathFindExtensionA(lpstrPathAndFile
);
1394 fodInfos
->ofnInfos
->nFileExtension
= (lpszTemp
) ? lpszTemp
- lpstrPathAndFile
+ 1 : 0;
1396 /* set the lpstrFileTitle */
1397 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
1399 LPSTR lpstrFileTitle
= COMDLG32_PathFindFileNameA(lpstrPathAndFile
);
1400 strncpy(fodInfos
->ofnInfos
->lpstrFileTitle
, lpstrFileTitle
, fodInfos
->ofnInfos
->nMaxFileTitle
);
1403 FILEDLG95_Clean(hwnd
);
1404 ret
= EndDialog(hwnd
, TRUE
);
1408 /* FIXME set error FNERR_BUFFERTOSMALL */
1409 FILEDLG95_Clean(hwnd
);
1410 ret
= EndDialog(hwnd
, FALSE
);
1418 if(lpsf
) IShellFolder_Release(lpsf
);
1422 /***********************************************************************
1423 * FILEDLG95_SHELL_Init
1425 * Initialisation of the shell objects
1427 static HRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
1429 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1434 * Initialisation of the FileOpenDialogInfos structure
1440 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
1442 /* Disable multi-select if flag not set */
1443 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
1445 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
1447 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
1448 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
1450 GetWindowRect(GetDlgItem(hwnd
,IDC_SHELLSTATIC
),&fodInfos
->ShellInfos
.rectView
);
1451 ScreenToClient(hwnd
,(LPPOINT
)&fodInfos
->ShellInfos
.rectView
.left
);
1452 ScreenToClient(hwnd
,(LPPOINT
)&fodInfos
->ShellInfos
.rectView
.right
);
1454 /* Construct the IShellBrowser interface */
1455 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
1460 /***********************************************************************
1461 * FILEDLG95_SHELL_ExecuteCommand
1463 * Change the folder option and refresh the view
1464 * If the function succeeds, the return value is nonzero.
1466 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
1468 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1471 TRACE("(0x%08x,%p)\n", hwnd
, lpVerb
);
1473 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
1478 CMINVOKECOMMANDINFO ci
;
1479 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
1480 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
1484 IContextMenu_InvokeCommand(pcm
, &ci
);
1485 IContextMenu_Release(pcm
);
1491 /***********************************************************************
1492 * FILEDLG95_SHELL_UpFolder
1494 * Browse to the specified object
1495 * If the function succeeds, the return value is nonzero.
1497 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
1499 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1503 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
1512 /***********************************************************************
1513 * FILEDLG95_SHELL_Clean
1515 * Cleans the memory used by shell objects
1517 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
1519 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1523 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
1525 /* clean Shell interfaces */
1526 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
1527 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
1528 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
1529 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
1530 if (fodInfos
->Shell
.FOIDataObject
)
1531 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
1534 /***********************************************************************
1535 * FILEDLG95_FILETYPE_Init
1537 * Initialisation of the file type combo box
1539 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
1541 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1545 if(fodInfos
->ofnInfos
->lpstrFilter
)
1547 int nFilters
= 0; /* number of filters */
1549 LPCSTR lpstrPos
= fodInfos
->ofnInfos
->lpstrFilter
;
1553 /* filter is a list... title\0ext\0......\0\0
1554 * Set the combo item text to the title and the item data
1557 LPCSTR lpstrDisplay
;
1561 if(! *lpstrPos
) break; /* end */
1562 lpstrDisplay
= lpstrPos
;
1563 lpstrPos
+= strlen(lpstrPos
) + 1;
1565 /* Copy the extensions */
1566 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
1567 if (!(lpstrExt
= (LPSTR
) MemAlloc(strlen(lpstrPos
)+1))) return E_FAIL
;
1568 strcpy(lpstrExt
,lpstrPos
);
1569 lpstrPos
+= strlen(lpstrPos
) + 1;
1571 /* Add the item at the end of the combo */
1572 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
1573 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
1577 * Set the current filter to the one specified
1578 * in the initialisation structure
1579 * FIXME: lpstrCustomFilter not handled at all
1582 /* set default filter index */
1583 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->ofnInfos
->lpstrCustomFilter
== NULL
)
1584 fodInfos
->ofnInfos
->nFilterIndex
= 1;
1586 /* First, check to make sure our index isn't out of bounds. */
1587 if ( fodInfos
->ofnInfos
->nFilterIndex
> nFilters
)
1588 fodInfos
->ofnInfos
->nFilterIndex
= nFilters
;
1590 /* Set the current index selection. */
1591 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->ofnInfos
->nFilterIndex
-1);
1593 /* Get the corresponding text string from the combo box. */
1594 lpstrFilter
= (LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
1595 fodInfos
->ofnInfos
->nFilterIndex
-1);
1597 if ((INT
)lpstrFilter
== CB_ERR
) /* control is empty */
1602 CRTDLL__strlwr(lpstrFilter
); /* lowercase */
1603 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc((strlen(lpstrFilter
)+1)*2);
1604 lstrcpyAtoW(fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpstrFilter
);
1610 /***********************************************************************
1611 * FILEDLG95_FILETYPE_OnCommand
1613 * WM_COMMAND of the file type combo box
1614 * If the function succeeds, the return value is nonzero.
1616 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
1618 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1626 /* Get the current item of the filetype combo box */
1627 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
1629 /* set the current filter index - indexed from 1 */
1630 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+ 1;
1632 /* Set the current filter with the current selection */
1633 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
1634 MemFree((LPVOID
)fodInfos
->ShellInfos
.lpstrCurrentFilter
);
1636 lpstrFilter
= (LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
1638 if((int)lpstrFilter
!= CB_ERR
)
1640 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc((strlen(lpstrFilter
)+1)*2);
1641 lstrcpyAtoW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,CRTDLL__strlwr(lpstrFilter
));
1642 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
1645 /* Refresh the actual view to display the included items*/
1646 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
1651 /***********************************************************************
1652 * FILEDLG95_FILETYPE_SearchExt
1654 * searches for a extension in the filetype box
1656 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCSTR lpstrExt
)
1658 int i
, iCount
= CBGetCount(hwnd
);
1660 TRACE("%s\n", lpstrExt
);
1662 if(iCount
!= CB_ERR
)
1664 for(i
=0;i
<iCount
;i
++)
1666 if(!strcasecmp(lpstrExt
,(LPSTR
)CBGetItemDataPtr(hwnd
,i
)))
1673 /***********************************************************************
1674 * FILEDLG95_FILETYPE_Clean
1676 * Clean the memory used by the filetype combo box
1678 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
1680 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1682 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
1686 /* Delete each string of the combo and their associated data */
1687 if(iCount
!= CB_ERR
)
1689 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
1691 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
1692 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
1695 /* Current filter */
1696 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
1697 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
1701 /***********************************************************************
1702 * FILEDLG95_LOOKIN_Init
1704 * Initialisation of the look in combo box
1706 static HRESULT
FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
1708 IShellFolder
*psfRoot
, *psfDrives
;
1709 IEnumIDList
*lpeRoot
, *lpeDrives
;
1710 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
1712 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
1716 liInfos
->iMaxIndentation
= 0;
1718 SetPropA(hwndCombo
, LookInInfosStr
, (HANDLE
) liInfos
);
1719 CBSetItemHeight(hwndCombo
,0,GetSystemMetrics(SM_CYSMICON
));
1721 /* Initialise data of Desktop folder */
1722 COMDLG32_SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
1723 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
1724 COMDLG32_SHFree(pidlTmp
);
1726 COMDLG32_SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
1728 COMDLG32_SHGetDesktopFolder(&psfRoot
);
1732 /* enumerate the contents of the desktop */
1733 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
1735 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
1737 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
1739 /* special handling for CSIDL_DRIVES */
1740 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
1742 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
1744 /* enumerate the drives */
1745 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
1747 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
1749 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
1750 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
1751 COMDLG32_SHFree(pidlAbsTmp
);
1752 COMDLG32_SHFree(pidlTmp1
);
1754 IEnumIDList_Release(lpeDrives
);
1756 IShellFolder_Release(psfDrives
);
1759 COMDLG32_SHFree(pidlTmp
);
1761 IEnumIDList_Release(lpeRoot
);
1765 IShellFolder_Release(psfRoot
);
1766 COMDLG32_SHFree(pidlDrives
);
1770 /***********************************************************************
1771 * FILEDLG95_LOOKIN_DrawItem
1773 * WM_DRAWITEM message handler
1775 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
1777 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
1778 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
1779 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
1783 HIMAGELIST ilItemImage
;
1785 LPSFOLDER tmpFolder
;
1788 LookInInfos
*liInfos
= (LookInInfos
*)GetPropA(pDIStruct
->hwndItem
,LookInInfosStr
);
1792 if(pDIStruct
->itemID
== -1)
1795 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
1796 pDIStruct
->itemID
)))
1800 if(pDIStruct
->itemID
== liInfos
->uSelectedItem
)
1802 ilItemImage
= (HIMAGELIST
) COMDLG32_SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
1805 sizeof (SHFILEINFOA
),
1806 SHGFI_PIDL
| SHGFI_SMALLICON
|
1807 SHGFI_OPENICON
| SHGFI_SYSICONINDEX
|
1808 SHGFI_DISPLAYNAME
);
1812 ilItemImage
= (HIMAGELIST
) COMDLG32_SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
1815 sizeof (SHFILEINFOA
),
1816 SHGFI_PIDL
| SHGFI_SMALLICON
|
1817 SHGFI_SYSICONINDEX
|
1821 /* Is this item selected ?*/
1822 if(pDIStruct
->itemState
& ODS_SELECTED
)
1824 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
1825 SetBkColor(pDIStruct
->hDC
,crHighLight
);
1826 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,(HBRUSH
)crHighLight
);
1830 SetTextColor(pDIStruct
->hDC
,crText
);
1831 SetBkColor(pDIStruct
->hDC
,crWin
);
1832 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,(HBRUSH
)crWin
);
1835 /* Do not indent item if drawing in the edit of the combo*/
1836 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
1839 ilItemImage
= (HIMAGELIST
) COMDLG32_SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
1842 sizeof (SHFILEINFOA
),
1843 SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_OPENICON
1844 | SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
);
1849 iIndentation
= tmpFolder
->m_iIndent
;
1851 /* Draw text and icon */
1853 /* Initialise the icon display area */
1854 rectIcon
.left
= pDIStruct
->rcItem
.left
+ ICONWIDTH
/2 * iIndentation
;
1855 rectIcon
.top
= pDIStruct
->rcItem
.top
;
1856 rectIcon
.right
= rectIcon
.left
+ ICONWIDTH
;
1857 rectIcon
.bottom
= pDIStruct
->rcItem
.bottom
;
1859 /* Initialise the text display area */
1860 rectText
.left
= rectIcon
.right
;
1861 rectText
.top
= pDIStruct
->rcItem
.top
+ YTEXTOFFSET
;
1862 rectText
.right
= pDIStruct
->rcItem
.right
+ XTEXTOFFSET
;
1863 rectText
.bottom
= pDIStruct
->rcItem
.bottom
;
1866 /* Draw the icon from the image list */
1867 COMDLG32_ImageList_Draw(ilItemImage
,
1874 /* Draw the associated text */
1875 if(sfi
.szDisplayName
)
1876 TextOutA(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,strlen(sfi
.szDisplayName
));
1882 /***********************************************************************
1883 * FILEDLG95_LOOKIN_OnCommand
1885 * LookIn combo box WM_COMMAND message handler
1886 * If the function succeeds, the return value is nonzero.
1888 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
1890 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1892 TRACE("%p\n", fodInfos
);
1898 LPSFOLDER tmpFolder
;
1901 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
1903 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
1908 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
1909 tmpFolder
->pidlItem
,
1921 /***********************************************************************
1922 * FILEDLG95_LOOKIN_AddItem
1924 * Adds an absolute pidl item to the lookin combo box
1925 * returns the index of the inserted item
1927 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
1929 LPITEMIDLIST pidlNext
;
1932 LookInInfos
*liInfos
;
1939 if(!(liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
)))
1942 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
1943 tmpFolder
->m_iIndent
= 0;
1945 /* Calculate the indentation of the item in the lookin*/
1947 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
1949 tmpFolder
->m_iIndent
++;
1952 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
); /* FIXME: memory leak*/
1954 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
1955 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
1957 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
1958 COMDLG32_SHGetFileInfoA((LPSTR
)pidl
,
1962 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
1963 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
1966 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
1970 /* Add the item at the end of the list */
1973 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
1975 /* Insert the item at the iInsertId position*/
1978 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
1981 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
1985 MemFree( tmpFolder
);
1990 /***********************************************************************
1991 * FILEDLG95_LOOKIN_InsertItemAfterParent
1993 * Insert an item below its parent
1995 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
1998 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
2003 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
2007 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
2010 /* Free pidlParent memory */
2011 COMDLG32_SHFree((LPVOID
)pidlParent
);
2013 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
2016 /***********************************************************************
2017 * FILEDLG95_LOOKIN_SelectItem
2019 * Adds an absolute pidl item to the lookin combo box
2020 * returns the index of the inserted item
2022 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
2025 LookInInfos
*liInfos
;
2029 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
2031 liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
);
2035 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
2036 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
2041 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
2042 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
2046 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
2048 if(iRemovedItem
< iItemPos
)
2053 CBSetCurSel(hwnd
,iItemPos
);
2054 liInfos
->uSelectedItem
= iItemPos
;
2060 /***********************************************************************
2061 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2063 * Remove the item with an expansion level over iExpansionLevel
2065 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
2069 LookInInfos
*liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
);
2073 if(liInfos
->iMaxIndentation
<= 2)
2076 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
2078 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
2079 COMDLG32_SHFree(tmpFolder
->pidlItem
);
2081 CBDeleteString(hwnd
,iItemPos
);
2082 liInfos
->iMaxIndentation
--;
2090 /***********************************************************************
2091 * FILEDLG95_LOOKIN_SearchItem
2093 * Search for pidl in the lookin combo box
2094 * returns the index of the found item
2096 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
2099 int iCount
= CBGetCount(hwnd
);
2103 if (iCount
!= CB_ERR
)
2107 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
2109 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
2111 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
2119 /***********************************************************************
2120 * FILEDLG95_LOOKIN_Clean
2122 * Clean the memory used by the lookin combo box
2124 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
2126 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2128 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
2132 /* Delete each string of the combo and their associated data */
2133 if (iCount
!= CB_ERR
)
2135 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
2137 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
2138 COMDLG32_SHFree(tmpFolder
->pidlItem
);
2140 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
2144 /* LookInInfos structure */
2145 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
2148 /***********************************************************************
2149 * FILEDLG95_FILENAME_FillFromSelection
2151 * fills the edit box from the cached DataObject
2153 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
2155 FileOpenDlgInfos
*fodInfos
;
2157 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nLength
= 0;
2158 char lpstrTemp
[MAX_PATH
];
2159 LPSTR lpstrAllFile
= NULL
, lpstrCurrFile
= NULL
;
2162 fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2164 /* Count how many files we have */
2165 nFileSelected
= GetNumSelected( fodInfos
->Shell
.FOIDataObject
);
2167 /* calculate the string length, count files */
2168 if (nFileSelected
>= 1)
2170 nLength
+= 3; /* first and last quotes, trailing \0 */
2171 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
2173 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
2177 /* get the total length of the selected file names*/
2178 lpstrTemp
[0] = '\0';
2179 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
, lpstrTemp
);
2181 if ( ! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
) ) /* Ignore folders */
2183 nLength
+= lstrlenA( lpstrTemp
) + 3;
2186 COMDLG32_SHFree( pidl
);
2191 /* allocate the buffer */
2192 if (nFiles
<= 1) nLength
= MAX_PATH
;
2193 lpstrAllFile
= (LPSTR
)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nLength
);
2194 lpstrAllFile
[0] = '\0';
2196 /* Generate the string for the edit control */
2199 lpstrCurrFile
= lpstrAllFile
;
2200 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
2202 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
2206 /* get the file name */
2207 lpstrTemp
[0] = '\0';
2208 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
, lpstrTemp
);
2210 if (! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
)) /* Ignore folders */
2214 *lpstrCurrFile
++ = '\"';
2215 lstrcpyA( lpstrCurrFile
, lpstrTemp
);
2216 lpstrCurrFile
+= lstrlenA( lpstrTemp
);
2217 lstrcpyA( lpstrCurrFile
, "\" " );
2222 lstrcpyA( lpstrAllFile
, lpstrTemp
);
2225 COMDLG32_SHFree( (LPVOID
) pidl
);
2230 SetWindowTextA( fodInfos
->DlgInfos
.hwndFileName
, lpstrAllFile
);
2231 HeapFree(GetProcessHeap(),0, lpstrAllFile
);
2235 /* copied from shell32 to avoid linking to it */
2236 static HRESULT
COMDLG32_StrRetToStrNA (LPVOID dest
, DWORD len
, LPSTRRET src
, LPITEMIDLIST pidl
)
2241 WideCharToMultiByte(CP_ACP
, 0, src
->u
.pOleStr
, -1, (LPSTR
)dest
, len
, NULL
, NULL
);
2242 COMDLG32_SHFree(src
->u
.pOleStr
);
2246 lstrcpynA((LPSTR
)dest
, src
->u
.cStr
, len
);
2249 case STRRET_OFFSETA
:
2250 lstrcpynA((LPSTR
)dest
, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, len
);
2254 FIXME("unknown type!\n");
2257 *(LPSTR
)dest
= '\0';
2264 /***********************************************************************
2265 * FILEDLG95_FILENAME_GetFileNames
2267 * copys the filenames to a 0-delimited string
2269 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPSTR
* lpstrFileList
, UINT
* sizeUsed
)
2271 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2272 UINT nStrCharCount
= 0; /* index in src buffer */
2273 UINT nFileIndex
= 0; /* index in dest buffer */
2274 UINT nFileCount
= 0; /* number of files */
2275 UINT nStrLen
= 0; /* length of string in edit control */
2276 LPSTR lpstrEdit
; /* buffer for string from edit control */
2280 /* get the filenames from the edit control */
2281 nStrLen
= SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0);
2282 lpstrEdit
= MemAlloc(nStrLen
+1);
2283 GetDlgItemTextA(hwnd
, IDC_FILENAME
, lpstrEdit
, nStrLen
+1);
2285 TRACE("nStrLen=%u str=%s\n", nStrLen
, lpstrEdit
);
2287 *lpstrFileList
= MemAlloc(nStrLen
);
2290 /* build 0-delimited file list from filenames*/
2291 while ( nStrCharCount
<= nStrLen
)
2293 if ( lpstrEdit
[nStrCharCount
]=='"' )
2296 while ((lpstrEdit
[nStrCharCount
]!='"') && (nStrCharCount
<= nStrLen
))
2298 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
2302 (*lpstrFileList
)[nFileIndex
++] = '\0';
2309 /* single, unquoted string */
2310 if ((nStrLen
> 0) && (*sizeUsed
== 0) )
2312 strcpy(*lpstrFileList
, lpstrEdit
);
2313 nFileIndex
= strlen(lpstrEdit
) + 1;
2314 (*sizeUsed
) = nFileIndex
;
2319 (*lpstrFileList
)[nFileIndex
] = '\0';
2326 #define SETDefFormatEtc(fe,cf,med) \
2328 (fe).cfFormat = cf;\
2329 (fe).dwAspect = DVASPECT_CONTENT; \
2336 * DATAOBJECT Helper functions
2339 /***********************************************************************
2340 * COMCTL32_ReleaseStgMedium
2342 * like ReleaseStgMedium from ole32
2344 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
2346 if(medium
.pUnkForRelease
)
2348 IUnknown_Release(medium
.pUnkForRelease
);
2352 GlobalUnlock(medium
.u
.hGlobal
);
2353 GlobalFree(medium
.u
.hGlobal
);
2357 /***********************************************************************
2358 * GetPidlFromDataObject
2360 * Return pidl(s) by number from the cached DataObject
2362 * nPidlIndex=0 gets the fully qualified root path
2364 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
2368 FORMATETC formatetc
;
2369 LPITEMIDLIST pidl
= NULL
;
2371 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
2373 /* Set the FORMATETC structure*/
2374 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
2376 /* Get the pidls from IDataObject */
2377 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
2379 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
2380 if(nPidlIndex
<= cida
->cidl
)
2382 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
2384 COMCTL32_ReleaseStgMedium(medium
);
2389 /***********************************************************************
2392 * Return the number of selected items in the DataObject.
2395 UINT
GetNumSelected( IDataObject
*doSelected
)
2399 FORMATETC formatetc
;
2401 TRACE("sv=%p\n", doSelected
);
2403 if (!doSelected
) return 0;
2405 /* Set the FORMATETC structure*/
2406 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
2408 /* Get the pidls from IDataObject */
2409 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
2411 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
2412 retVal
= cida
->cidl
;
2413 COMCTL32_ReleaseStgMedium(medium
);
2423 /***********************************************************************
2426 * Get the pidl's display name (relative to folder) and
2427 * put it in lpstrFileName.
2429 * Return NOERROR on success,
2433 HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPSTR lpstrFileName
)
2438 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
2443 COMDLG32_SHGetDesktopFolder(&lpsf
);
2444 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
2445 IShellFolder_Release(lpsf
);
2449 /* Get the display name of the pidl relative to the folder */
2450 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
2452 return COMDLG32_StrRetToStrNA(lpstrFileName
, MAX_PATH
, &str
, pidl
);
2457 /***********************************************************************
2458 * GetShellFolderFromPidl
2460 * pidlRel is the item pidl relative
2461 * Return the IShellFolder of the absolute pidl
2463 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
2465 IShellFolder
*psf
= NULL
,*psfParent
;
2467 TRACE("%p\n", pidlAbs
);
2469 if(SUCCEEDED(COMDLG32_SHGetDesktopFolder(&psfParent
)))
2472 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
2474 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
2476 IShellFolder_Release(psfParent
);
2480 /* return the desktop */
2486 /***********************************************************************
2489 * Return the LPITEMIDLIST to the parent of the pidl in the list
2491 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
2493 LPITEMIDLIST pidlParent
;
2495 TRACE("%p\n", pidl
);
2497 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
2498 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
2503 /***********************************************************************
2506 * returns the pidl of the file name relative to folder
2507 * NULL if an error occured
2509 LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPCSTR lpcstrFileName
)
2513 WCHAR lpwstrDirName
[MAX_PATH
];
2515 TRACE("sf=%p file=%s\n", lpsf
, lpcstrFileName
);
2517 if(!lpcstrFileName
) return NULL
;
2519 MultiByteToWideChar(CP_ACP
,MB_PRECOMPOSED
,lpcstrFileName
,-1,(LPWSTR
)lpwstrDirName
,MAX_PATH
);
2523 COMDLG32_SHGetDesktopFolder(&lpsf
);
2524 pidl
= GetPidlFromName(lpsf
, lpcstrFileName
);
2525 IShellFolder_Release(lpsf
);
2529 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, (LPWSTR
)lpwstrDirName
, &ulEaten
, &pidl
, NULL
);
2536 BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPITEMIDLIST pidl
)
2538 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
2541 TRACE("%p, %p\n", psf
, pidl
);
2543 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
2545 TRACE("-- 0x%08lx 0x%08lx\n", uAttr
, ret
);
2546 /* see documentation shell 4.1*/
2547 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
2550 /***********************************************************************
2551 * BrowseSelectedFolder
2553 static BOOL
BrowseSelectedFolder(HWND hwnd
)
2555 BOOL bBrowseSelFolder
= FALSE
;
2556 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2560 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
2562 LPITEMIDLIST pidlSelection
;
2564 /* get the file selected */
2565 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
2566 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
2568 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
2569 pidlSelection
, SBSP_RELATIVE
) ) )
2571 MessageBoxA( hwnd
, "Path does not exist", fodInfos
->ofnInfos
->lpstrTitle
,
2572 MB_OK
| MB_ICONEXCLAMATION
);
2575 bBrowseSelFolder
= TRUE
;
2577 COMDLG32_SHFree( pidlSelection
);
2580 return bBrowseSelFolder
;
2584 * Memory allocation methods */
2585 static void *MemAlloc(UINT size
)
2587 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
2590 static void MemFree(void *mem
)
2594 HeapFree(GetProcessHeap(),0,mem
);