Implemented localeconv() with libc function.
[wine.git] / dlls / commdlg / filedlg95.c
blob9e9fcf63d7eb4b6348264a07853b92c1f0fc5d09
1 /*
2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: 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)
54 #include "config.h"
55 #include "wine/port.h"
57 #include <ctype.h>
58 #include <stdlib.h>
59 #include <stdio.h>
60 #include <string.h>
62 #define NONAMELESSUNION
63 #define NONAMELESSSTRUCT
64 #include "winbase.h"
65 #include "winternl.h"
66 #include "winnls.h"
67 #include "wine/unicode.h"
68 #include "commdlg.h"
69 #include "dlgs.h"
70 #include "cdlg.h"
71 #include "wine/debug.h"
72 #include "cderr.h"
73 #include "shellapi.h"
74 #include "shlguid.h"
75 #include "filedlgbrowser.h"
76 #include "shlwapi.h"
77 #include "wine/obj_contextmenu.h"
79 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
81 #define UNIMPLEMENTED_FLAGS \
82 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
83 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING | OFN_EXTENSIONDIFFERENT |\
84 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
85 OFN_NOTESTFILECREATE | OFN_OVERWRITEPROMPT /*| OFN_USEMONIKERS*/)
87 #define IsHooked(fodInfos) \
88 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
89 /***********************************************************************
90 * Data structure and global variables
92 typedef struct SFolder
94 int m_iImageIndex; /* Index of picture in image list */
95 HIMAGELIST hImgList;
96 int m_iIndent; /* Indentation index */
97 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
99 } SFOLDER,*LPSFOLDER;
101 typedef struct tagLookInInfo
103 int iMaxIndentation;
104 UINT uSelectedItem;
105 } LookInInfos;
108 /***********************************************************************
109 * Defines and global variables
112 /* Draw item constant */
113 #define ICONWIDTH 18
114 #define XTEXTOFFSET 3
116 /* AddItem flags*/
117 #define LISTEND -1
119 /* SearchItem methods */
120 #define SEARCH_PIDL 1
121 #define SEARCH_EXP 2
122 #define ITEM_NOTFOUND -1
124 /* Undefined windows message sent by CreateViewObject*/
125 #define WM_GETISHELLBROWSER WM_USER+7
127 /* NOTE
128 * Those macros exist in windowsx.h. However, you can't really use them since
129 * they rely on the UNICODE defines and can't be used inside Wine itself.
132 /* Combo box macros */
133 #define CBAddString(hwnd,str) \
134 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
135 #define CBAddStringW(hwnd,str) \
136 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
138 #define CBInsertString(hwnd,str,pos) \
139 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
141 #define CBDeleteString(hwnd,pos) \
142 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
144 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
145 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
147 #define CBGetItemDataPtr(hwnd,iItemId) \
148 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
150 #define CBGetLBText(hwnd,iItemId,str) \
151 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
153 #define CBGetCurSel(hwnd) \
154 SendMessageA(hwnd,CB_GETCURSEL,0,0);
156 #define CBSetCurSel(hwnd,pos) \
157 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
159 #define CBGetCount(hwnd) \
160 SendMessageA(hwnd,CB_GETCOUNT,0,0);
161 #define CBShowDropDown(hwnd,show) \
162 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
163 #define CBSetItemHeight(hwnd,index,height) \
164 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
167 const char *FileOpenDlgInfosStr = "FileOpenDlgInfos"; /* windows property description string */
168 const char *LookInInfosStr = "LookInInfos"; /* LOOKIN combo box property */
170 /***********************************************************************
171 * Prototypes
174 /* Internal functions used by the dialog */
175 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
176 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
177 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
178 BOOL FILEDLG95_OnOpen(HWND hwnd);
179 static LRESULT FILEDLG95_InitControls(HWND hwnd);
180 static void FILEDLG95_Clean(HWND hwnd);
182 /* Functions used by the shell navigation */
183 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
184 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
185 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
186 static void FILEDLG95_SHELL_Clean(HWND hwnd);
187 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
189 /* Functions used by the filetype combo box */
190 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
191 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
192 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
193 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
195 /* Functions used by the Look In combo box */
196 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo);
197 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
198 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
199 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
200 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
201 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
202 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
203 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
204 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
206 /* Miscellaneous tool functions */
207 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
208 HRESULT GetFileName(HWND hwnd, LPITEMIDLIST pidl, LPSTR lpstrFileName);
209 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
210 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
211 LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
213 /* Shell memory allocation */
214 static void *MemAlloc(UINT size);
215 static void MemFree(void *mem);
217 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos);
218 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
219 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode);
220 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
221 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
222 static BOOL BrowseSelectedFolder(HWND hwnd);
224 /***********************************************************************
225 * GetFileName95
227 * Creates an Open common dialog box that lets the user select
228 * the drive, directory, and the name of a file or set of files to open.
230 * IN : The FileOpenDlgInfos structure associated with the dialog
231 * OUT : TRUE on success
232 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
234 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
237 LRESULT lRes;
238 LPCVOID template;
239 HRSRC hRes;
240 HANDLE hDlgTmpl = 0;
242 /* test for missing functionality */
243 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
245 FIXME("Flags 0x%08lx not yet implemented\n",
246 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
249 /* Create the dialog from a template */
251 if(!(hRes = FindResourceA(COMDLG32_hInstance,MAKEINTRESOURCEA(NEWFILEOPENORD),RT_DIALOGA)))
253 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
254 return FALSE;
256 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
257 !(template = LockResource( hDlgTmpl )))
259 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
260 return FALSE;
263 /* old style hook messages */
264 if (IsHooked(fodInfos))
266 fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
267 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
268 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
269 fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
272 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
273 (LPDLGTEMPLATEA) template,
274 fodInfos->ofnInfos->hwndOwner,
275 FileOpenDlgProc95,
276 (LPARAM) fodInfos);
278 /* Unable to create the dialog */
279 if( lRes == -1)
280 return FALSE;
282 return lRes;
285 /***********************************************************************
286 * GetFileDialog95A
288 * Call GetFileName95 with this structure and clean the memory.
290 * IN : The OPENFILENAMEA initialisation structure passed to
291 * GetOpenFileNameA win api function (see filedlg.c)
293 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
295 BOOL ret;
296 FileOpenDlgInfos fodInfos;
297 LPSTR lpstrSavDir = NULL;
298 LPWSTR title = NULL;
299 LPWSTR defext = NULL;
300 LPWSTR filter = NULL;
301 LPWSTR customfilter = NULL;
303 /* Initialize FileOpenDlgInfos structure */
304 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
306 /* Pass in the original ofn */
307 fodInfos.ofnInfos = ofn;
309 /* save current directory */
310 if (ofn->Flags & OFN_NOCHANGEDIR)
312 lpstrSavDir = MemAlloc(MAX_PATH);
313 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
316 fodInfos.unicode = FALSE;
318 /* convert all the input strings to unicode */
319 if(ofn->lpstrInitialDir)
321 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
322 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
323 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
325 else
326 fodInfos.initdir = NULL;
328 if(ofn->lpstrFile)
330 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
331 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
333 else
334 fodInfos.filename = NULL;
336 if(ofn->lpstrDefExt)
338 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
339 defext = MemAlloc((len+1)*sizeof(WCHAR));
340 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
342 fodInfos.defext = defext;
344 if(ofn->lpstrTitle)
346 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
347 title = MemAlloc((len+1)*sizeof(WCHAR));
348 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
350 fodInfos.title = title;
352 if (ofn->lpstrFilter)
354 LPCSTR s;
355 int n, len;
357 /* filter is a list... title\0ext\0......\0\0 */
358 s = ofn->lpstrFilter;
359 while (*s) s = s+strlen(s)+1;
360 s++;
361 n = s - ofn->lpstrFilter;
362 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
363 filter = MemAlloc(len*sizeof(WCHAR));
364 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
366 fodInfos.filter = filter;
368 /* convert lpstrCustomFilter */
369 if (ofn->lpstrCustomFilter)
371 LPCSTR s;
372 int n, len;
374 /* filter is a list... title\0ext\0......\0\0 */
375 s = ofn->lpstrCustomFilter;
376 while (*s) s = s+strlen(s)+1;
377 s++;
378 n = s - ofn->lpstrCustomFilter;
379 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
380 customfilter = MemAlloc(len*sizeof(WCHAR));
381 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
383 fodInfos.customfilter = customfilter;
385 /* Initialize the dialog property */
386 fodInfos.DlgInfos.dwDlgProp = 0;
387 fodInfos.DlgInfos.hwndCustomDlg = NULL;
389 switch(iDlgType)
391 case OPEN_DIALOG :
392 ret = GetFileName95(&fodInfos);
393 break;
394 case SAVE_DIALOG :
395 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
396 ret = GetFileName95(&fodInfos);
397 break;
398 default :
399 ret = 0;
402 if (lpstrSavDir)
404 SetCurrentDirectoryA(lpstrSavDir);
405 MemFree(lpstrSavDir);
408 if(title)
409 MemFree(title);
410 if(defext)
411 MemFree(defext);
412 if(filter)
413 MemFree(filter);
414 if(customfilter)
415 MemFree(customfilter);
416 if(fodInfos.initdir)
417 MemFree(fodInfos.initdir);
419 if(fodInfos.filename)
420 MemFree(fodInfos.filename);
422 TRACE("selected file: %s\n",ofn->lpstrFile);
424 return ret;
427 /***********************************************************************
428 * GetFileDialog95W
430 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
431 * Call GetFileName95 with this structure and clean the memory.
433 * FIXME: lpstrCustomFilter has to be converted back
436 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
438 BOOL ret;
439 FileOpenDlgInfos fodInfos;
440 LPSTR lpstrSavDir = NULL;
442 /* Initialize FileOpenDlgInfos structure */
443 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
445 /* Pass in the original ofn */
446 fodInfos.ofnInfos = (LPOPENFILENAMEA) ofn;
448 fodInfos.title = ofn->lpstrTitle;
449 fodInfos.defext = ofn->lpstrDefExt;
450 fodInfos.filter = ofn->lpstrFilter;
451 fodInfos.customfilter = ofn->lpstrCustomFilter;
453 /* convert string arguments, save others */
454 if(ofn->lpstrFile)
456 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
457 strncpyW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
459 else
460 fodInfos.filename = NULL;
462 if(ofn->lpstrInitialDir)
464 DWORD len = strlenW(ofn->lpstrInitialDir);
465 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
466 strcpyW(fodInfos.initdir,ofn->lpstrInitialDir);
468 else
469 fodInfos.initdir = NULL;
471 /* save current directory */
472 if (ofn->Flags & OFN_NOCHANGEDIR)
474 lpstrSavDir = MemAlloc(MAX_PATH);
475 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
478 fodInfos.unicode = TRUE;
480 switch(iDlgType)
482 case OPEN_DIALOG :
483 ret = GetFileName95(&fodInfos);
484 break;
485 case SAVE_DIALOG :
486 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
487 ret = GetFileName95(&fodInfos);
488 break;
489 default :
490 ret = 0;
493 if (lpstrSavDir)
495 SetCurrentDirectoryA(lpstrSavDir);
496 MemFree(lpstrSavDir);
499 /* restore saved IN arguments and convert OUT arguments back */
500 MemFree(fodInfos.filename);
501 MemFree(fodInfos.initdir);
502 return ret;
505 void ArrangeCtrlPositions( HWND hwndChildDlg, HWND hwndParentDlg)
507 HWND hwndChild,hwndStc32;
508 RECT rectParent, rectChild, rectCtrl, rectStc32, rectTemp;
509 POINT ptMoveCtl;
510 POINT ptParentClient;
512 TRACE("\n");
514 ptMoveCtl.x = ptMoveCtl.y = 0;
515 hwndStc32=GetDlgItem(hwndChildDlg,stc32);
516 GetClientRect(hwndParentDlg,&rectParent);
517 GetClientRect(hwndChildDlg,&rectChild);
520 There are two possibilities to add components to the default file dialog box.
522 By default, all the new components are added below the standard dialog box (the else case).
524 However, if there is a static text component with the stc32 id, a special case happens.
525 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
526 in the window and the cx and cy indicate how to size the window.
527 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
528 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
531 if(hwndStc32)
533 GetWindowRect(hwndStc32,&rectStc32);
534 MapWindowPoints(0, hwndChildDlg,(LPPOINT)&rectStc32,2);
535 CopyRect(&rectTemp,&rectStc32);
537 if ((rectParent.right-rectParent.left)>(rectChild.right-rectChild.left)) {
538 ptParentClient.x = (rectParent.right-rectParent.left)+ ((rectChild.right-rectChild.left) - (rectStc32.right-rectStc32.left));
539 } else {
540 ptParentClient.x = max((rectParent.right-rectParent.left),(rectChild.right-rectChild.left));
542 ptMoveCtl.x = (rectParent.right-rectParent.left) ;
544 if ((rectParent.bottom-rectParent.top)>(rectChild.bottom-rectChild.top)) {
545 ptParentClient.y = (rectParent.bottom-rectParent.top) + (rectChild.bottom-rectChild.top) - (rectStc32.bottom-rectStc32.top);
546 } else {
547 ptParentClient.y = max((rectParent.bottom-rectParent.top),(rectChild.bottom-rectChild.top));
549 ptMoveCtl.y = (rectParent.bottom-rectParent.top) ;
551 else
553 SetRectEmpty(&rectTemp);
554 /* After some tests it appears that windows never extends the width in that case */
555 ptParentClient.x = (rectParent.right-rectParent.left);
556 ptParentClient.y = (rectParent.bottom-rectParent.top);
557 /* Some applications use an empty child window, add this test to prevent garbage */
558 if (GetWindow(hwndChildDlg,GW_CHILD))
559 ptParentClient.y += (rectChild.bottom-rectChild.top);
560 ptMoveCtl.y = rectParent.bottom-rectParent.top;
561 ptMoveCtl.x = 0;
563 /* Set the new size of the window from the extra space needed */
564 SetRect(&rectParent,rectParent.left,rectParent.top,rectParent.left+ptParentClient.x,rectParent.top+ptParentClient.y);
565 AdjustWindowRectEx( &rectParent,GetWindowLongA(hwndParentDlg,GWL_STYLE),FALSE,GetWindowLongA(hwndParentDlg,GWL_EXSTYLE));
567 SetWindowPos(hwndChildDlg, 0, 0,0, ptParentClient.x,ptParentClient.y, SWP_NOZORDER );
568 SetWindowPos(hwndParentDlg, 0, rectParent.left,rectParent.top, (rectParent.right- rectParent.left),
569 (rectParent.bottom-rectParent.top),SWP_NOMOVE | SWP_NOZORDER);
572 This part moves the child components below the file dialog box if stc32 is not present
573 and place them accordinf to stc32 if it is present.
575 hwndChild = GetWindow(hwndChildDlg,GW_CHILD);
576 if (hwndChild )
580 if(hwndChild != hwndStc32)
582 if (GetWindowLongA( hwndChild, GWL_STYLE ) & WS_MAXIMIZE)
583 continue;
584 GetWindowRect(hwndChild,&rectCtrl);
585 MapWindowPoints( 0, hwndParentDlg,(LPPOINT)&rectCtrl,2);
587 If stc32 is present, moves the child components as required.
589 if ((rectCtrl.left >= rectTemp.right) && ((rectCtrl.left+ptMoveCtl.x)<rectParent.right)){
590 rectCtrl.left += ptMoveCtl.x;
591 rectCtrl.right +=ptMoveCtl.x;
593 if ((rectCtrl.top >= rectTemp.bottom) && ((rectCtrl.top+ptMoveCtl.y)<rectParent.bottom)){
594 rectCtrl.top += ptMoveCtl.y;
595 rectCtrl.bottom += ptMoveCtl.y;
598 SetWindowPos( hwndChild, 0, rectCtrl.left, rectCtrl.top,
599 rectCtrl.right-rectCtrl.left,rectCtrl.bottom-rectCtrl.top,
600 SWP_NOSIZE | SWP_NOZORDER );
602 } while ((hwndChild=GetWindow( hwndChild, GW_HWNDNEXT )) != NULL);
606 This part moves the components of the default file dialog box according to the stc32 coordinates.
608 hwndChild = GetWindow(hwndParentDlg,GW_CHILD);
609 if(hwndStc32)
611 GetWindowRect(hwndStc32,&rectStc32);
612 MapWindowPoints( 0, hwndChildDlg,(LPPOINT)&rectStc32,2);
613 ptMoveCtl.x = rectStc32.left - 0;
614 ptMoveCtl.y = rectStc32.top - 0;
615 if (hwndChild )
619 if(hwndChild != hwndChildDlg)
621 if (GetWindowLongA( hwndChild, GWL_STYLE ) & WS_MAXIMIZE)
622 continue;
623 GetWindowRect(hwndChild,&rectCtrl);
624 MapWindowPoints( 0, hwndParentDlg,(LPPOINT)&rectCtrl,2);
626 rectCtrl.left += ptMoveCtl.x;
627 rectCtrl.right += ptMoveCtl.x;
628 rectCtrl.top += ptMoveCtl.y;
629 rectCtrl.bottom += ptMoveCtl.y;
631 SetWindowPos( hwndChild, 0, rectCtrl.left, rectCtrl.top,
632 rectCtrl.right-rectCtrl.left,rectCtrl.bottom-rectCtrl.top,
633 SWP_NOSIZE |SWP_NOZORDER );
635 } while ((hwndChild=GetWindow( hwndChild, GW_HWNDNEXT )) != NULL);
641 INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
643 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(GetParent(hwnd),FileOpenDlgInfosStr);
645 #if 0
646 TRACE("0x%04x\n", uMsg);
647 #endif
649 switch(uMsg)
651 case WM_INITDIALOG:
653 /* Hide caption since some program may leave it */
654 DWORD Style = GetWindowLongA(hwnd, GWL_STYLE);
655 if (Style & WS_CAPTION) SetWindowLongA(hwnd, GWL_STYLE, Style & (~WS_CAPTION));
657 fodInfos = (FileOpenDlgInfos *)lParam;
658 lParam = (LPARAM) fodInfos->ofnInfos;
659 ArrangeCtrlPositions(hwnd,GetParent(hwnd));
661 /* If the help button and the readonly button are hidden
662 we have to resize the dialog before calling the hook procedure
663 because some apps use the size to resize the window.
665 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
666 (!(fodInfos->ofnInfos->Flags &
667 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
669 RECT rectDlg, rectHelp, rectCancel;
670 GetWindowRect(hwnd, &rectDlg);
671 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
672 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
673 /* subtract the height of the help button plus the space between
674 the help button and the cancel button to the height of the dialog */
675 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
676 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
677 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
680 if(fodInfos && IsHooked(fodInfos))
681 return CallWindowProcA((WNDPROC)fodInfos->ofnInfos->lpfnHook,hwnd,uMsg,wParam,lParam);
682 return 0;
686 if(fodInfos && IsHooked(fodInfos))
687 return CallWindowProcA((WNDPROC)fodInfos->ofnInfos->lpfnHook,hwnd,uMsg,wParam,lParam);
689 return DefWindowProcA(hwnd,uMsg,wParam,lParam);
692 HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
694 LPCVOID template;
695 HRSRC hRes;
696 HANDLE hDlgTmpl = 0;
697 HWND hChildDlg = 0;
699 TRACE("\n");
702 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
703 * structure's hInstance parameter is not a HINSTANCE, but
704 * instead a pointer to a template resource to use.
706 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATE ||
707 fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
709 HINSTANCE hinst;
710 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
712 hinst = 0;
713 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
715 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
716 return NULL;
719 else
721 hinst = fodInfos->ofnInfos->hInstance;
722 if(fodInfos->unicode)
724 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
725 hRes = FindResourceW( hinst, ofn->lpTemplateName, RT_DIALOGW);
727 else
729 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
730 hRes = FindResourceA( hinst, ofn->lpTemplateName, RT_DIALOGA);
732 if (!hRes)
734 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
735 return NULL;
737 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
738 !(template = LockResource( hDlgTmpl )))
740 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
741 return NULL;
744 hChildDlg= CreateDialogIndirectParamA(hinst, template,
745 hwnd, FileOpenDlgProcUserTemplate, (LPARAM)fodInfos);
746 if(hChildDlg)
748 ShowWindow(hChildDlg,SW_SHOW);
749 return hChildDlg;
752 else if( IsHooked(fodInfos))
754 RECT rectHwnd;
755 struct {
756 DLGTEMPLATE tmplate;
757 WORD menu,class,title;
758 } temp;
759 GetClientRect(hwnd,&rectHwnd);
760 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS;
761 temp.tmplate.dwExtendedStyle = 0;
762 temp.tmplate.cdit = 0;
763 temp.tmplate.x = 0;
764 temp.tmplate.y = 0;
765 temp.tmplate.cx = rectHwnd.right-rectHwnd.left;
766 temp.tmplate.cy = rectHwnd.bottom-rectHwnd.top;
767 temp.menu = temp.class = temp.title = 0;
769 hChildDlg = CreateDialogIndirectParamA(fodInfos->ofnInfos->hInstance,&temp.tmplate,
770 hwnd, FileOpenDlgProcUserTemplate, (LPARAM)fodInfos);
772 return hChildDlg;
774 return NULL;
777 /***********************************************************************
778 * SendCustomDlgNotificationMessage
780 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
783 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
785 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
787 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
789 if(!fodInfos) return 0;
791 if(fodInfos->unicode)
792 FIXME("sending OPENFILENAMEA structure. Hook is expecting OPENFILENAMEW!\n");
794 if(fodInfos->DlgInfos.hwndCustomDlg)
796 OFNOTIFYA ofnNotify;
797 HRESULT ret;
798 ofnNotify.hdr.hwndFrom=hwndParentDlg;
799 ofnNotify.hdr.idFrom=0;
800 ofnNotify.hdr.code = uCode;
801 ofnNotify.lpOFN = fodInfos->ofnInfos;
802 TRACE("CALL NOTIFY for %x\n", uCode);
803 ret = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
804 TRACE("RET NOTIFY\n");
805 return ret;
807 return TRUE;
810 HRESULT FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPSTR buffer)
812 UINT sizeUsed = 0, n, total;
813 LPWSTR lpstrFileList = NULL;
814 WCHAR lpstrCurrentDir[MAX_PATH];
815 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
817 TRACE("CDM_GETFILEPATH:\n");
819 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
820 return -1;
822 /* get path and filenames */
823 SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent,lpstrCurrentDir);
824 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
826 TRACE("path >%s< filespec >%s< %d files\n",
827 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
829 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
830 NULL, 0, NULL, NULL);
831 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
832 NULL, 0, NULL, NULL);
834 /* Prepend the current path */
835 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
836 buffer, size, NULL, NULL);
838 if(n<size)
840 /* 'n' includes trailing \0 */
841 buffer[n-1] = '\\';
842 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
843 &buffer[n], size-n, NULL, NULL);
845 MemFree(lpstrFileList);
847 TRACE("returned -> %s\n",debugstr_a(buffer));
849 return total;
852 HRESULT FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPSTR buffer)
854 UINT sizeUsed = 0;
855 LPWSTR lpstrFileList = NULL;
857 TRACE("CDM_GETSPEC:\n");
859 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
860 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed, buffer, size, NULL, NULL);
861 MemFree(lpstrFileList);
863 return sizeUsed;
866 /***********************************************************************
867 * FILEDLG95_HandleCustomDialogMessages
869 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
871 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
873 char lpstrPath[MAX_PATH];
874 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
875 if(!fodInfos) return -1;
877 switch(uMsg)
879 case CDM_GETFILEPATH:
880 return FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPSTR)lParam);
882 case CDM_GETFOLDERPATH:
883 TRACE("CDM_GETFOLDERPATH:\n");
884 SHGetPathFromIDListA(fodInfos->ShellInfos.pidlAbsCurrent,lpstrPath);
885 if ((LPSTR)lParam!=NULL)
886 lstrcpynA((LPSTR)lParam,lpstrPath,(int)wParam);
887 return strlen(lpstrPath);
889 case CDM_GETSPEC:
890 return FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
892 case CDM_SETCONTROLTEXT:
893 TRACE("CDM_SETCONTROLTEXT:\n");
894 if ( 0 != lParam )
895 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
896 return TRUE;
898 case CDM_HIDECONTROL:
899 case CDM_SETDEFEXT:
900 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
901 return -1;
903 return TRUE;
906 /***********************************************************************
907 * FileOpenDlgProc95
909 * File open dialog procedure
911 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
913 #if 0
914 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
915 #endif
917 switch(uMsg)
919 case WM_INITDIALOG:
921 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
923 /* Adds the FileOpenDlgInfos in the property list of the dialog
924 so it will be easily accessible through a GetPropA(...) */
925 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
927 fodInfos->DlgInfos.hwndCustomDlg =
928 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
930 FILEDLG95_InitControls(hwnd);
931 FILEDLG95_FillControls(hwnd, wParam, lParam);
932 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
933 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
934 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
935 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
936 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE);
937 return 0;
939 case WM_COMMAND:
940 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
941 case WM_DRAWITEM:
943 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
945 case IDC_LOOKIN:
946 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
947 return TRUE;
950 return FALSE;
952 case WM_GETISHELLBROWSER:
953 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
955 case WM_DESTROY:
956 RemovePropA(hwnd, FileOpenDlgInfosStr);
957 return FALSE;
959 case WM_NOTIFY:
961 LPNMHDR lpnmh = (LPNMHDR)lParam;
962 UINT stringId = -1;
964 /* set up the button tooltips strings */
965 if(TTN_GETDISPINFOA == lpnmh->code )
967 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
968 switch(lpnmh->idFrom )
970 /* Up folder button */
971 case FCIDM_TB_UPFOLDER:
972 stringId = IDS_UPFOLDER;
973 break;
974 /* New folder button */
975 case FCIDM_TB_NEWFOLDER:
976 stringId = IDS_NEWFOLDER;
977 break;
978 /* List option button */
979 case FCIDM_TB_SMALLICON:
980 stringId = IDS_LISTVIEW;
981 break;
982 /* Details option button */
983 case FCIDM_TB_REPORTVIEW:
984 stringId = IDS_REPORTVIEW;
985 break;
986 /* Desktop button */
987 case FCIDM_TB_DESKTOP:
988 stringId = IDS_TODESKTOP;
989 break;
990 default:
991 stringId = 0;
993 lpdi->hinst = COMDLG32_hInstance;
994 lpdi->lpszText = (LPSTR) stringId;
996 return FALSE;
998 default :
999 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1000 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1001 return FALSE;
1005 /***********************************************************************
1006 * FILEDLG95_InitControls
1008 * WM_INITDIALOG message handler (before hook notification)
1010 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1012 int win2000plus = 0;
1013 int win98plus = 0;
1014 int handledPath = FALSE;
1015 OSVERSIONINFOA osVi;
1016 const WCHAR szwSlash[] = { '\\', 0 };
1017 const WCHAR szwStar[] = { '*',0 };
1019 TBBUTTON tbb[] =
1021 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0 },
1022 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
1023 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0 },
1024 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
1025 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0 },
1026 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
1027 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0 },
1028 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
1029 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
1031 TBADDBITMAP tba[2];
1032 RECT rectTB;
1033 RECT rectlook;
1034 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1036 tba[0].hInst = HINST_COMMCTRL;
1037 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1038 tba[1].hInst = COMDLG32_hInstance;
1039 tba[1].nID = 800;
1041 TRACE("%p\n", fodInfos);
1043 /* Get windows version emulating */
1044 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1045 GetVersionExA(&osVi);
1046 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1047 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1048 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1049 win2000plus = (osVi.dwMajorVersion > 4);
1050 if (win2000plus) win98plus = TRUE;
1052 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1054 /* Get the hwnd of the controls */
1055 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1056 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1057 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1059 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1060 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1062 /* construct the toolbar */
1063 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1064 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1066 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1067 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1068 rectTB.left = rectlook.right;
1069 rectTB.top = rectlook.top-1;
1071 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1072 WS_CHILD | WS_GROUP | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1073 0, 0, 150, 26, hwnd, (HMENU) IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1075 SetWindowPos(fodInfos->DlgInfos.hwndTB, 0,
1076 rectTB.left,rectTB.top, rectTB.right-rectTB.left, rectTB.bottom-rectTB.top,
1077 SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER );
1079 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1081 /* FIXME: use TB_LOADIMAGES when implemented */
1082 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1083 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1084 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1086 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1087 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1089 /* Set the window text with the text specified in the OPENFILENAME structure */
1090 if(fodInfos->title)
1092 SetWindowTextW(hwnd,fodInfos->title);
1094 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1096 SetWindowTextA(hwnd,"Save");
1099 /* Initialise the file name edit control */
1100 handledPath = FALSE;
1101 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1103 if(fodInfos->filename)
1105 /* 1. If win2000 or higher and filename contains a path, use it
1106 in preference over the lpstrInitialDir */
1107 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1108 WCHAR tmpBuf[MAX_PATH];
1109 WCHAR *nameBit;
1110 DWORD result;
1112 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1113 if (result) {
1115 /* nameBit is always shorter than the original filename */
1116 strcpyW(fodInfos->filename,nameBit);
1118 *nameBit = 0x00;
1119 if (fodInfos->initdir == NULL)
1120 MemFree(fodInfos->initdir);
1121 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1122 strcpyW(fodInfos->initdir, tmpBuf);
1123 handledPath = TRUE;
1124 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1125 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1127 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1129 } else {
1130 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1134 /* 2. (All platforms) If initdir is not null, then use it */
1135 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1136 (*fodInfos->initdir!=0x00))
1138 /* Work out the proper path as supplied one might be relative */
1139 /* (Here because supplying '.' as dir browses to My Computer) */
1140 if (handledPath==FALSE) {
1141 WCHAR tmpBuf[MAX_PATH];
1142 WCHAR tmpBuf2[MAX_PATH];
1143 WCHAR *nameBit;
1144 DWORD result;
1146 strcpyW(tmpBuf, fodInfos->initdir);
1147 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1148 strcatW(tmpBuf, szwSlash);
1150 strcatW(tmpBuf, szwStar);
1151 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1152 if (result) {
1153 *nameBit = 0x00;
1154 if (fodInfos->initdir)
1155 MemFree(fodInfos->initdir);
1156 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1157 strcpyW(fodInfos->initdir, tmpBuf2);
1158 handledPath = TRUE;
1159 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1164 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1165 (*fodInfos->initdir==0x00)))
1167 /* 3. All except w2k+: if filename contains a path use it */
1168 if (!win2000plus && fodInfos->filename &&
1169 *fodInfos->filename &&
1170 strpbrkW(fodInfos->filename, szwSlash)) {
1171 WCHAR tmpBuf[MAX_PATH];
1172 WCHAR *nameBit;
1173 DWORD result;
1175 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1176 tmpBuf, &nameBit);
1177 if (result) {
1178 int len;
1180 /* nameBit is always shorter than the original filename */
1181 strcpyW(fodInfos->filename, nameBit);
1182 *nameBit = 0x00;
1184 len = strlenW(tmpBuf);
1185 if(fodInfos->initdir)
1186 MemFree(fodInfos->initdir);
1187 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1188 strcpyW(fodInfos->initdir, tmpBuf);
1190 handledPath = TRUE;
1191 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1192 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1194 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1197 /* 4. win98+ and win2000+ if any files of specified filter types in
1198 current directory, use it */
1199 if ( win98plus && handledPath == FALSE &&
1200 fodInfos->filter && *fodInfos->filter) {
1202 BOOL searchMore = TRUE;
1203 LPCWSTR lpstrPos = fodInfos->filter;
1204 WIN32_FIND_DATAW FindFileData;
1205 HANDLE hFind;
1207 while (searchMore)
1209 /* filter is a list... title\0ext\0......\0\0 */
1211 /* Skip the title */
1212 if(! *lpstrPos) break; /* end */
1213 lpstrPos += strlenW(lpstrPos) + 1;
1215 /* See if any files exist in the current dir with this extension */
1216 if(! *lpstrPos) break; /* end */
1218 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1220 if (hFind == INVALID_HANDLE_VALUE) {
1221 /* None found - continue search */
1222 lpstrPos += strlenW(lpstrPos) + 1;
1224 } else {
1225 searchMore = FALSE;
1227 if(fodInfos->initdir)
1228 MemFree(fodInfos->initdir);
1229 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1230 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1232 handledPath = TRUE;
1233 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1234 debugstr_w(lpstrPos));
1235 break;
1240 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1242 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1243 if (handledPath == FALSE && (win2000plus || win98plus)) {
1244 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1246 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1248 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1250 /* last fallback */
1251 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1252 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1253 } else {
1254 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1256 } else {
1257 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1259 handledPath = TRUE;
1260 } else if (handledPath==FALSE) {
1261 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1262 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1263 handledPath = TRUE;
1264 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1267 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1269 /* Must the open as read only check box be checked ?*/
1270 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1272 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1275 /* Must the open as read only check box be hid ?*/
1276 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1278 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1281 /* Must the help button be hid ?*/
1282 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1284 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1287 /* Resize the height, if open as read only checkbox ad help button
1288 are hidden and we are not using a custom template nor a customDialog
1290 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1291 (!(fodInfos->ofnInfos->Flags &
1292 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1293 (!fodInfos->DlgInfos.hwndCustomDlg ))
1295 RECT rectDlg, rectHelp, rectCancel;
1296 GetWindowRect(hwnd, &rectDlg);
1297 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1298 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1299 /* subtract the height of the help button plus the space between
1300 the help button and the cancel button to the height of the dialog */
1301 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1302 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1303 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1305 /* change Open to Save FIXME: use resources */
1306 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1308 SetDlgItemTextA(hwnd,IDOK,"&Save");
1309 SetDlgItemTextA(hwnd,IDC_LOOKINSTATIC,"Save &in");
1311 return 0;
1314 /***********************************************************************
1315 * FILEDLG95_FillControls
1317 * WM_INITDIALOG message handler (after hook notification)
1319 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1321 LPITEMIDLIST pidlItemId = NULL;
1323 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1325 TRACE("dir=%s file=%s\n",
1326 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1328 /* Get the initial directory pidl */
1330 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1332 WCHAR path[MAX_PATH];
1334 GetCurrentDirectoryW(MAX_PATH,path);
1335 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1338 /* Initialise shell objects */
1339 FILEDLG95_SHELL_Init(hwnd);
1341 /* Initialize the Look In combo box */
1342 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1344 /* Initialize the filter combo box */
1345 FILEDLG95_FILETYPE_Init(hwnd);
1347 /* Browse to the initial directory */
1348 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1350 /* Free pidlItem memory */
1351 COMDLG32_SHFree(pidlItemId);
1353 return TRUE;
1355 /***********************************************************************
1356 * FILEDLG95_Clean
1358 * Regroups all the cleaning functions of the filedlg
1360 void FILEDLG95_Clean(HWND hwnd)
1362 FILEDLG95_FILETYPE_Clean(hwnd);
1363 FILEDLG95_LOOKIN_Clean(hwnd);
1364 FILEDLG95_SHELL_Clean(hwnd);
1366 /***********************************************************************
1367 * FILEDLG95_OnWMCommand
1369 * WM_COMMAND message handler
1371 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1373 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1374 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1375 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1377 switch(wID)
1379 /* OK button */
1380 case IDOK:
1381 FILEDLG95_OnOpen(hwnd);
1382 break;
1383 /* Cancel button */
1384 case IDCANCEL:
1385 FILEDLG95_Clean(hwnd);
1386 EndDialog(hwnd, FALSE);
1387 break;
1388 /* Filetype combo box */
1389 case IDC_FILETYPE:
1390 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1391 break;
1392 /* LookIn combo box */
1393 case IDC_LOOKIN:
1394 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1395 break;
1397 /* --- toolbar --- */
1398 /* Up folder button */
1399 case FCIDM_TB_UPFOLDER:
1400 FILEDLG95_SHELL_UpFolder(hwnd);
1401 break;
1402 /* New folder button */
1403 case FCIDM_TB_NEWFOLDER:
1404 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDER);
1405 break;
1406 /* List option button */
1407 case FCIDM_TB_SMALLICON:
1408 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLIST);
1409 break;
1410 /* Details option button */
1411 case FCIDM_TB_REPORTVIEW:
1412 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILS);
1413 break;
1414 /* Details option button */
1415 case FCIDM_TB_DESKTOP:
1416 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1417 break;
1419 case IDC_FILENAME:
1420 break;
1423 /* Do not use the listview selection anymore */
1424 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1425 return 0;
1428 /***********************************************************************
1429 * FILEDLG95_OnWMGetIShellBrowser
1431 * WM_GETISHELLBROWSER message handler
1433 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1436 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1438 TRACE("\n");
1440 SetWindowLongA(hwnd,DWL_MSGRESULT,(LONG)fodInfos->Shell.FOIShellBrowser);
1442 return TRUE;
1446 /***********************************************************************
1447 * FILEDLG95_SendFileOK
1449 * Sends the CDN_FILEOK notification if required
1451 * RETURNS
1452 * TRUE if the dialog should close
1453 * FALSE if the dialog should not be closed
1455 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1457 /* ask the hook if we can close */
1458 if(IsHooked(fodInfos))
1460 TRACE("---\n");
1461 /* First send CDN_FILEOK as MSDN doc says */
1462 SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1464 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1465 CallWindowProcA((WNDPROC)fodInfos->ofnInfos->lpfnHook,
1466 fodInfos->DlgInfos.hwndCustomDlg,
1467 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1468 if (GetWindowLongA(fodInfos->DlgInfos.hwndCustomDlg, DWL_MSGRESULT))
1470 TRACE("canceled\n");
1471 return FALSE;
1474 return TRUE;
1477 /***********************************************************************
1478 * FILEDLG95_OnOpenMultipleFiles
1480 * Handles the opening of multiple files.
1482 * FIXME
1483 * check destination buffer size
1485 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1487 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1488 UINT nCount, nSizePath;
1489 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1491 TRACE("\n");
1493 if(fodInfos->unicode)
1495 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1496 ofn->lpstrFile[0] = '\0';
1498 else
1500 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1501 ofn->lpstrFile[0] = '\0';
1504 SHGetPathFromIDListW( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1506 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1507 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1508 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1510 LPWSTR lpstrTemp = lpstrFileList;
1512 for ( nCount = 0; nCount < nFileCount; nCount++ )
1514 LPITEMIDLIST pidl;
1516 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1517 if (!pidl)
1519 WCHAR lpstrNotFound[100];
1520 WCHAR lpstrMsg[100];
1521 WCHAR tmp[400];
1522 WCHAR nl[] = {'\n',0};
1524 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1525 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1527 strcpyW(tmp, lpstrTemp);
1528 strcatW(tmp, nl);
1529 strcatW(tmp, lpstrNotFound);
1530 strcatW(tmp, nl);
1531 strcatW(tmp, lpstrMsg);
1533 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1534 return FALSE;
1537 /* move to the next file in the list of files */
1538 lpstrTemp += strlenW(lpstrTemp) + 1;
1539 COMDLG32_SHFree(pidl);
1543 nSizePath = strlenW(lpstrPathSpec) + 1;
1544 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1546 /* For "oldstyle" dialog the components have to
1547 be spearated by blanks (not '\0'!) and short
1548 filenames have to be used! */
1549 FIXME("Components have to be separated by blanks");
1551 if(fodInfos->unicode)
1553 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1554 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1555 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1557 else
1559 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1561 if (ofn->lpstrFile != NULL)
1563 WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1564 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1565 if (ofn->nMaxFile > nSizePath)
1567 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1568 ofn->lpstrFile + nSizePath,
1569 ofn->nMaxFile - nSizePath, NULL, NULL);
1574 fodInfos->ofnInfos->nFileOffset = nSizePath + 1;
1575 fodInfos->ofnInfos->nFileExtension = 0;
1577 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1578 return FALSE;
1580 /* clean and exit */
1581 FILEDLG95_Clean(hwnd);
1582 return EndDialog(hwnd,TRUE);
1585 /***********************************************************************
1586 * FILEDLG95_OnOpen
1588 * Ok button WM_COMMAND message handler
1590 * If the function succeeds, the return value is nonzero.
1592 #define ONOPEN_BROWSE 1
1593 #define ONOPEN_OPEN 2
1594 #define ONOPEN_SEARCH 3
1595 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1597 char strMsgTitle[MAX_PATH];
1598 char strMsgText [MAX_PATH];
1599 if (idCaption)
1600 LoadStringA(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle));
1601 else
1602 strMsgTitle[0] = '\0';
1603 LoadStringA(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText));
1604 MessageBoxA(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1607 BOOL FILEDLG95_OnOpen(HWND hwnd)
1609 LPWSTR lpstrFileList;
1610 UINT nFileCount = 0;
1611 UINT sizeUsed = 0;
1612 BOOL ret = TRUE;
1613 WCHAR lpstrPathAndFile[MAX_PATH];
1614 WCHAR lpstrTemp[MAX_PATH];
1615 LPSHELLFOLDER lpsf = NULL;
1616 int nOpenAction;
1617 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1619 TRACE("hwnd=%p\n", hwnd);
1621 /* get the files from the edit control */
1622 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1624 /* try if the user selected a folder in the shellview */
1625 if(nFileCount == 0)
1627 BrowseSelectedFolder(hwnd);
1628 return FALSE;
1631 if(nFileCount > 1)
1633 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1634 goto ret;
1637 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1640 Step 1: Build a complete path name from the current folder and
1641 the filename or path in the edit box.
1642 Special cases:
1643 - the path in the edit box is a root path
1644 (with or without drive letter)
1645 - the edit box contains ".." (or a path with ".." in it)
1648 /* Get the current directory name */
1649 if (!SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1651 /* we are in a special folder, default to desktop */
1652 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, lpstrPathAndFile)))
1654 /* last fallback */
1655 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1658 PathAddBackslashW(lpstrPathAndFile);
1660 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1662 /* if the user specifyed a fully qualified path use it */
1663 if(PathIsRelativeW(lpstrFileList))
1665 strcatW(lpstrPathAndFile, lpstrFileList);
1667 else
1669 /* does the path have a drive letter? */
1670 if (PathGetDriveNumberW(lpstrFileList) == -1)
1671 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1672 else
1673 strcpyW(lpstrPathAndFile, lpstrFileList);
1676 /* resolve "." and ".." */
1677 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1678 strcpyW(lpstrPathAndFile, lpstrTemp);
1679 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1681 MemFree(lpstrFileList);
1684 Step 2: here we have a cleaned up path
1686 We have to parse the path step by step to see if we have to browse
1687 to a folder if the path points to a directory or the last
1688 valid element is a directory.
1690 valid variables:
1691 lpstrPathAndFile: cleaned up path
1694 nOpenAction = ONOPEN_BROWSE;
1696 /* dont apply any checks with OFN_NOVALIDATE */
1698 LPWSTR lpszTemp, lpszTemp1;
1699 LPITEMIDLIST pidl = NULL;
1700 WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1702 /* check for invalid chars */
1703 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1705 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1706 ret = FALSE;
1707 goto ret;
1710 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1712 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1713 while (lpszTemp1)
1715 LPSHELLFOLDER lpsfChild;
1716 WCHAR lpwstrTemp[MAX_PATH];
1717 DWORD dwEaten, dwAttributes;
1718 LPWSTR p;
1720 strcpyW(lpwstrTemp, lpszTemp);
1721 p = PathFindNextComponentW(lpwstrTemp);
1723 if (!p) break; /* end of path */
1725 *p = 0;
1726 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1728 if(*lpszTemp==0)
1730 WCHAR wszWild[] = { '*', '?', 0 };
1731 /* if the last element is a wildcard do a search */
1732 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1734 nOpenAction = ONOPEN_SEARCH;
1735 break;
1738 lpszTemp1 = lpszTemp;
1740 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1742 if(lstrlenW(lpwstrTemp)==2) PathAddBackslashW(lpwstrTemp);
1744 dwAttributes = SFGAO_FOLDER;
1745 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1747 /* the path component is valid, we have a pidl of the next path component */
1748 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1749 if(dwAttributes & SFGAO_FOLDER)
1751 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1753 ERR("bind to failed\n"); /* should not fail */
1754 break;
1756 IShellFolder_Release(lpsf);
1757 lpsf = lpsfChild;
1758 lpsfChild = NULL;
1760 else
1762 TRACE("value\n");
1764 /* end dialog, return value */
1765 nOpenAction = ONOPEN_OPEN;
1766 break;
1768 COMDLG32_SHFree(pidl);
1769 pidl = NULL;
1771 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1773 if(*lpszTemp) /* points to trailing null for last path element */
1775 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1777 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1778 break;
1781 else
1783 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1784 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1786 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1787 break;
1790 /* change to the current folder */
1791 nOpenAction = ONOPEN_OPEN;
1792 break;
1794 else
1796 nOpenAction = ONOPEN_OPEN;
1797 break;
1800 if(pidl) COMDLG32_SHFree(pidl);
1804 Step 3: here we have a cleaned up and validated path
1806 valid variables:
1807 lpsf: ShellFolder bound to the rightmost valid path component
1808 lpstrPathAndFile: cleaned up path
1809 nOpenAction: action to do
1811 TRACE("end validate sf=%p\n", lpsf);
1813 switch(nOpenAction)
1815 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1816 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1818 int iPos;
1819 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1820 DWORD len;
1822 /* replace the current filter */
1823 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1824 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1825 len = strlenW(lpszTemp)+1;
1826 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1827 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1829 /* set the filter cb to the extension when possible */
1830 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1831 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1833 /* fall through */
1834 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1835 TRACE("ONOPEN_BROWSE\n");
1837 IPersistFolder2 * ppf2;
1838 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1840 LPITEMIDLIST pidlCurrent;
1841 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1842 IPersistFolder2_Release(ppf2);
1843 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1845 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1847 else if( nOpenAction == ONOPEN_SEARCH )
1849 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1851 COMDLG32_SHFree(pidlCurrent);
1854 ret = FALSE;
1855 break;
1856 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
1857 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
1859 /* add default extension */
1860 if (fodInfos->defext)
1862 if (! *PathFindExtensionW(lpstrPathAndFile))
1864 /* only add "." in case a default extension does exist */
1865 if (*fodInfos->defext != '\0')
1867 const WCHAR szwDot[] = {'.',0};
1868 int PathLength = strlenW(lpstrPathAndFile);
1870 strcatW(lpstrPathAndFile, szwDot);
1871 strcatW(lpstrPathAndFile, fodInfos->defext);
1873 /* if file does not exist try without extension */
1874 if (!PathFileExistsW(lpstrPathAndFile))
1875 lpstrPathAndFile[PathLength] = '\0';
1880 /* Check that the size of the file does not exceed buffer size.
1881 (Allow for extra \0 if OFN_MULTISELECT is set.) */
1882 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
1883 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
1885 LPWSTR lpszTemp;
1887 /* fill destination buffer */
1888 if (fodInfos->ofnInfos->lpstrFile)
1890 if(fodInfos->unicode)
1892 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1894 strncpyW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
1895 if (ofn->Flags & OFN_ALLOWMULTISELECT)
1896 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
1898 else
1900 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1902 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
1903 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1904 if (ofn->Flags & OFN_ALLOWMULTISELECT)
1905 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
1909 /* set filename offset */
1910 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1911 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
1913 /* set extension offset */
1914 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
1915 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
1917 /* set the lpstrFileTitle */
1918 if(fodInfos->ofnInfos->lpstrFileTitle)
1920 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
1921 if(fodInfos->unicode)
1923 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1924 strncpyW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
1926 else
1928 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1929 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
1930 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
1934 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1935 goto ret;
1937 TRACE("close\n");
1938 FILEDLG95_Clean(hwnd);
1939 ret = EndDialog(hwnd, TRUE);
1941 else
1943 /* FIXME set error FNERR_BUFFERTOSMALL */
1944 FILEDLG95_Clean(hwnd);
1945 ret = EndDialog(hwnd, FALSE);
1947 goto ret;
1949 break;
1952 ret:
1953 if(lpsf) IShellFolder_Release(lpsf);
1954 return ret;
1957 /***********************************************************************
1958 * FILEDLG95_SHELL_Init
1960 * Initialisation of the shell objects
1962 static HRESULT FILEDLG95_SHELL_Init(HWND hwnd)
1964 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1966 TRACE("\n");
1969 * Initialisation of the FileOpenDialogInfos structure
1972 /* Shell */
1974 /*ShellInfos */
1975 fodInfos->ShellInfos.hwndOwner = hwnd;
1977 /* Disable multi-select if flag not set */
1978 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
1980 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
1982 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
1983 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
1985 GetWindowRect(GetDlgItem(hwnd,IDC_SHELLSTATIC),&fodInfos->ShellInfos.rectView);
1986 ScreenToClient(hwnd,(LPPOINT)&fodInfos->ShellInfos.rectView.left);
1987 ScreenToClient(hwnd,(LPPOINT)&fodInfos->ShellInfos.rectView.right);
1989 /* Construct the IShellBrowser interface */
1990 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
1992 return NOERROR;
1995 /***********************************************************************
1996 * FILEDLG95_SHELL_ExecuteCommand
1998 * Change the folder option and refresh the view
1999 * If the function succeeds, the return value is nonzero.
2001 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2003 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2005 IContextMenu * pcm;
2006 TRACE("(%p,%p)\n", hwnd, lpVerb);
2008 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2009 SVGIO_BACKGROUND,
2010 &IID_IContextMenu,
2011 (LPVOID*)&pcm)))
2013 CMINVOKECOMMANDINFO ci;
2014 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2015 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2016 ci.lpVerb = lpVerb;
2017 ci.hwnd = hwnd;
2019 IContextMenu_InvokeCommand(pcm, &ci);
2020 IContextMenu_Release(pcm);
2023 return FALSE;
2026 /***********************************************************************
2027 * FILEDLG95_SHELL_UpFolder
2029 * Browse to the specified object
2030 * If the function succeeds, the return value is nonzero.
2032 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2034 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2036 TRACE("\n");
2038 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2039 NULL,
2040 SBSP_PARENT)))
2042 return TRUE;
2044 return FALSE;
2047 /***********************************************************************
2048 * FILEDLG95_SHELL_BrowseToDesktop
2050 * Browse to the Desktop
2051 * If the function succeeds, the return value is nonzero.
2053 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2055 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2056 LPITEMIDLIST pidl;
2057 HRESULT hres;
2059 TRACE("\n");
2061 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2062 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2063 COMDLG32_SHFree(pidl);
2064 return SUCCEEDED(hres);
2066 /***********************************************************************
2067 * FILEDLG95_SHELL_Clean
2069 * Cleans the memory used by shell objects
2071 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2073 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2075 TRACE("\n");
2077 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2079 /* clean Shell interfaces */
2080 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2081 IShellView_Release(fodInfos->Shell.FOIShellView);
2082 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2083 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2084 if (fodInfos->Shell.FOIDataObject)
2085 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2088 /***********************************************************************
2089 * FILEDLG95_FILETYPE_Init
2091 * Initialisation of the file type combo box
2093 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2095 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2097 TRACE("\n");
2099 if(fodInfos->filter)
2101 int nFilters = 0; /* number of filters */
2102 LPWSTR lpstrFilter;
2103 LPCWSTR lpstrPos = fodInfos->filter;
2105 for(;;)
2107 /* filter is a list... title\0ext\0......\0\0
2108 * Set the combo item text to the title and the item data
2109 * to the ext
2111 LPCWSTR lpstrDisplay;
2112 LPWSTR lpstrExt;
2114 /* Get the title */
2115 if(! *lpstrPos) break; /* end */
2116 lpstrDisplay = lpstrPos;
2117 lpstrPos += strlenW(lpstrPos) + 1;
2119 /* Copy the extensions */
2120 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2121 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2122 strcpyW(lpstrExt,lpstrPos);
2123 lpstrPos += strlenW(lpstrPos) + 1;
2125 /* Add the item at the end of the combo */
2126 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2127 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2128 nFilters++;
2131 * Set the current filter to the one specified
2132 * in the initialisation structure
2133 * FIXME: lpstrCustomFilter not handled at all
2136 /* set default filter index */
2137 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2138 fodInfos->ofnInfos->nFilterIndex = 1;
2140 /* First, check to make sure our index isn't out of bounds. */
2141 if ( fodInfos->ofnInfos->nFilterIndex > nFilters )
2142 fodInfos->ofnInfos->nFilterIndex = nFilters;
2144 /* Set the current index selection. */
2145 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->ofnInfos->nFilterIndex-1);
2147 /* Get the corresponding text string from the combo box. */
2148 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2149 fodInfos->ofnInfos->nFilterIndex-1);
2151 if ((INT)lpstrFilter == CB_ERR) /* control is empty */
2152 lpstrFilter = NULL;
2154 if(lpstrFilter)
2156 DWORD len;
2157 CharLowerW(lpstrFilter); /* lowercase */
2158 len = strlenW(lpstrFilter)+1;
2159 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2160 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2163 return NOERROR;
2166 /***********************************************************************
2167 * FILEDLG95_FILETYPE_OnCommand
2169 * WM_COMMAND of the file type combo box
2170 * If the function succeeds, the return value is nonzero.
2172 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2174 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2176 switch(wNotifyCode)
2178 case CBN_SELENDOK:
2180 LPWSTR lpstrFilter;
2182 /* Get the current item of the filetype combo box */
2183 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2185 /* set the current filter index - indexed from 1 */
2186 fodInfos->ofnInfos->nFilterIndex = iItem + 1;
2188 /* Set the current filter with the current selection */
2189 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2190 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2192 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2193 iItem);
2194 if((int)lpstrFilter != CB_ERR)
2196 DWORD len;
2197 CharLowerW(lpstrFilter); /* lowercase */
2198 len = strlenW(lpstrFilter)+1;
2199 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2200 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2201 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2204 /* Refresh the actual view to display the included items*/
2205 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2208 return FALSE;
2210 /***********************************************************************
2211 * FILEDLG95_FILETYPE_SearchExt
2213 * searches for a extension in the filetype box
2215 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2217 int i, iCount = CBGetCount(hwnd);
2219 TRACE("%s\n", debugstr_w(lpstrExt));
2221 if(iCount != CB_ERR)
2223 for(i=0;i<iCount;i++)
2225 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2226 return i;
2229 return -1;
2232 /***********************************************************************
2233 * FILEDLG95_FILETYPE_Clean
2235 * Clean the memory used by the filetype combo box
2237 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2239 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2240 int iPos;
2241 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2243 TRACE("\n");
2245 /* Delete each string of the combo and their associated data */
2246 if(iCount != CB_ERR)
2248 for(iPos = iCount-1;iPos>=0;iPos--)
2250 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2251 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2254 /* Current filter */
2255 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2256 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2260 /***********************************************************************
2261 * FILEDLG95_LOOKIN_Init
2263 * Initialisation of the look in combo box
2265 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2267 IShellFolder *psfRoot, *psfDrives;
2268 IEnumIDList *lpeRoot, *lpeDrives;
2269 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2271 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2273 TRACE("\n");
2275 liInfos->iMaxIndentation = 0;
2277 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2279 /* set item height for both text field and listbox */
2280 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2281 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2283 /* Initialise data of Desktop folder */
2284 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2285 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2286 COMDLG32_SHFree(pidlTmp);
2288 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2290 SHGetDesktopFolder(&psfRoot);
2292 if (psfRoot)
2294 /* enumerate the contents of the desktop */
2295 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2297 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2299 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2301 /* special handling for CSIDL_DRIVES */
2302 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2304 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2306 /* enumerate the drives */
2307 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2309 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2311 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2312 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2313 COMDLG32_SHFree(pidlAbsTmp);
2314 COMDLG32_SHFree(pidlTmp1);
2316 IEnumIDList_Release(lpeDrives);
2318 IShellFolder_Release(psfDrives);
2321 COMDLG32_SHFree(pidlTmp);
2323 IEnumIDList_Release(lpeRoot);
2327 IShellFolder_Release(psfRoot);
2328 COMDLG32_SHFree(pidlDrives);
2329 return NOERROR;
2332 /***********************************************************************
2333 * FILEDLG95_LOOKIN_DrawItem
2335 * WM_DRAWITEM message handler
2337 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2339 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2340 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2341 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2342 RECT rectText;
2343 RECT rectIcon;
2344 SHFILEINFOA sfi;
2345 HIMAGELIST ilItemImage;
2346 int iIndentation;
2347 TEXTMETRICA tm;
2348 LPSFOLDER tmpFolder;
2351 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2353 TRACE("\n");
2355 if(pDIStruct->itemID == -1)
2356 return 0;
2358 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2359 pDIStruct->itemID)))
2360 return 0;
2363 if(pDIStruct->itemID == liInfos->uSelectedItem)
2365 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2367 &sfi,
2368 sizeof (SHFILEINFOA),
2369 SHGFI_PIDL | SHGFI_SMALLICON |
2370 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2371 SHGFI_DISPLAYNAME );
2373 else
2375 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2377 &sfi,
2378 sizeof (SHFILEINFOA),
2379 SHGFI_PIDL | SHGFI_SMALLICON |
2380 SHGFI_SYSICONINDEX |
2381 SHGFI_DISPLAYNAME);
2384 /* Is this item selected ? */
2385 if(pDIStruct->itemState & ODS_SELECTED)
2387 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2388 SetBkColor(pDIStruct->hDC,crHighLight);
2389 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2391 else
2393 SetTextColor(pDIStruct->hDC,crText);
2394 SetBkColor(pDIStruct->hDC,crWin);
2395 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2398 /* Do not indent item if drawing in the edit of the combo */
2399 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2401 iIndentation = 0;
2402 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2404 &sfi,
2405 sizeof (SHFILEINFOA),
2406 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2407 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2410 else
2412 iIndentation = tmpFolder->m_iIndent;
2414 /* Draw text and icon */
2416 /* Initialise the icon display area */
2417 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2418 rectIcon.top = pDIStruct->rcItem.top;
2419 rectIcon.right = rectIcon.left + ICONWIDTH;
2420 rectIcon.bottom = pDIStruct->rcItem.bottom;
2422 /* Initialise the text display area */
2423 GetTextMetricsA(pDIStruct->hDC, &tm);
2424 rectText.left = rectIcon.right;
2425 rectText.top =
2426 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2427 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2428 rectText.bottom =
2429 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2431 /* Draw the icon from the image list */
2432 ImageList_Draw(ilItemImage,
2433 sfi.iIcon,
2434 pDIStruct->hDC,
2435 rectIcon.left,
2436 rectIcon.top,
2437 ILD_TRANSPARENT );
2439 /* Draw the associated text */
2440 if(sfi.szDisplayName)
2441 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2444 return NOERROR;
2447 /***********************************************************************
2448 * FILEDLG95_LOOKIN_OnCommand
2450 * LookIn combo box WM_COMMAND message handler
2451 * If the function succeeds, the return value is nonzero.
2453 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2455 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2457 TRACE("%p\n", fodInfos);
2459 switch(wNotifyCode)
2461 case CBN_SELENDOK:
2463 LPSFOLDER tmpFolder;
2464 int iItem;
2466 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2468 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2469 iItem)))
2470 return FALSE;
2473 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2474 tmpFolder->pidlItem,
2475 SBSP_ABSOLUTE)))
2477 return TRUE;
2479 break;
2483 return FALSE;
2486 /***********************************************************************
2487 * FILEDLG95_LOOKIN_AddItem
2489 * Adds an absolute pidl item to the lookin combo box
2490 * returns the index of the inserted item
2492 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2494 LPITEMIDLIST pidlNext;
2495 SHFILEINFOA sfi;
2496 SFOLDER *tmpFolder;
2497 LookInInfos *liInfos;
2499 TRACE("%08x\n", iInsertId);
2501 if(!pidl)
2502 return -1;
2504 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2505 return -1;
2507 tmpFolder = MemAlloc(sizeof(SFOLDER));
2508 tmpFolder->m_iIndent = 0;
2510 /* Calculate the indentation of the item in the lookin*/
2511 pidlNext = pidl;
2512 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2514 tmpFolder->m_iIndent++;
2517 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2519 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2520 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2522 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2523 SHGetFileInfoA((LPSTR)pidl,
2525 &sfi,
2526 sizeof(sfi),
2527 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2528 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2530 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2532 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2534 int iItemID;
2536 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2538 /* Add the item at the end of the list */
2539 if(iInsertId < 0)
2541 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2543 /* Insert the item at the iInsertId position*/
2544 else
2546 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2549 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2550 return iItemID;
2553 COMDLG32_SHFree( tmpFolder->pidlItem );
2554 MemFree( tmpFolder );
2555 return -1;
2559 /***********************************************************************
2560 * FILEDLG95_LOOKIN_InsertItemAfterParent
2562 * Insert an item below its parent
2564 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2567 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2568 int iParentPos;
2570 TRACE("\n");
2572 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2574 if(iParentPos < 0)
2576 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2579 /* Free pidlParent memory */
2580 COMDLG32_SHFree((LPVOID)pidlParent);
2582 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2585 /***********************************************************************
2586 * FILEDLG95_LOOKIN_SelectItem
2588 * Adds an absolute pidl item to the lookin combo box
2589 * returns the index of the inserted item
2591 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2593 int iItemPos;
2594 LookInInfos *liInfos;
2596 TRACE("\n");
2598 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2600 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2602 if(iItemPos < 0)
2604 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2605 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2608 else
2610 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2611 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2613 int iRemovedItem;
2615 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2616 break;
2617 if(iRemovedItem < iItemPos)
2618 iItemPos--;
2622 CBSetCurSel(hwnd,iItemPos);
2623 liInfos->uSelectedItem = iItemPos;
2625 return 0;
2629 /***********************************************************************
2630 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2632 * Remove the item with an expansion level over iExpansionLevel
2634 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2636 int iItemPos;
2638 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2640 TRACE("\n");
2642 if(liInfos->iMaxIndentation <= 2)
2643 return -1;
2645 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2647 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2648 COMDLG32_SHFree(tmpFolder->pidlItem);
2649 MemFree(tmpFolder);
2650 CBDeleteString(hwnd,iItemPos);
2651 liInfos->iMaxIndentation--;
2653 return iItemPos;
2656 return -1;
2659 /***********************************************************************
2660 * FILEDLG95_LOOKIN_SearchItem
2662 * Search for pidl in the lookin combo box
2663 * returns the index of the found item
2665 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2667 int i = 0;
2668 int iCount = CBGetCount(hwnd);
2670 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2672 if (iCount != CB_ERR)
2674 for(;i<iCount;i++)
2676 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2678 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2679 return i;
2680 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2681 return i;
2685 return -1;
2688 /***********************************************************************
2689 * FILEDLG95_LOOKIN_Clean
2691 * Clean the memory used by the lookin combo box
2693 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2695 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2696 int iPos;
2697 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2699 TRACE("\n");
2701 /* Delete each string of the combo and their associated data */
2702 if (iCount != CB_ERR)
2704 for(iPos = iCount-1;iPos>=0;iPos--)
2706 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
2707 COMDLG32_SHFree(tmpFolder->pidlItem);
2708 MemFree(tmpFolder);
2709 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
2713 /* LookInInfos structure */
2714 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
2717 /***********************************************************************
2718 * FILEDLG95_FILENAME_FillFromSelection
2720 * fills the edit box from the cached DataObject
2722 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
2724 FileOpenDlgInfos *fodInfos;
2725 LPITEMIDLIST pidl;
2726 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
2727 char lpstrTemp[MAX_PATH];
2728 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
2730 TRACE("\n");
2731 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2733 /* Count how many files we have */
2734 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
2736 /* calculate the string length, count files */
2737 if (nFileSelected >= 1)
2739 nLength += 3; /* first and last quotes, trailing \0 */
2740 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2742 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2744 if (pidl)
2746 /* get the total length of the selected file names */
2747 lpstrTemp[0] = '\0';
2748 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2750 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
2752 nLength += strlen( lpstrTemp ) + 3;
2753 nFiles++;
2755 COMDLG32_SHFree( pidl );
2760 /* allocate the buffer */
2761 if (nFiles <= 1) nLength = MAX_PATH;
2762 lpstrAllFile = (LPSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
2763 lpstrAllFile[0] = '\0';
2765 /* Generate the string for the edit control */
2766 if(nFiles >= 1)
2768 lpstrCurrFile = lpstrAllFile;
2769 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2771 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2773 if (pidl)
2775 /* get the file name */
2776 lpstrTemp[0] = '\0';
2777 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2779 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
2781 if ( nFiles > 1)
2783 *lpstrCurrFile++ = '\"';
2784 strcpy( lpstrCurrFile, lpstrTemp );
2785 lpstrCurrFile += strlen( lpstrTemp );
2786 strcpy( lpstrCurrFile, "\" " );
2787 lpstrCurrFile += 2;
2789 else
2791 strcpy( lpstrAllFile, lpstrTemp );
2794 COMDLG32_SHFree( (LPVOID) pidl );
2797 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
2799 HeapFree(GetProcessHeap(),0, lpstrAllFile );
2803 /* copied from shell32 to avoid linking to it */
2804 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
2806 switch (src->uType)
2808 case STRRET_WSTR:
2809 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
2810 COMDLG32_SHFree(src->u.pOleStr);
2811 break;
2813 case STRRET_CSTR:
2814 lstrcpynA((LPSTR)dest, src->u.cStr, len);
2815 break;
2817 case STRRET_OFFSET:
2818 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
2819 break;
2821 default:
2822 FIXME("unknown type!\n");
2823 if (len)
2825 *(LPSTR)dest = '\0';
2827 return(FALSE);
2829 return S_OK;
2832 /***********************************************************************
2833 * FILEDLG95_FILENAME_GetFileNames
2835 * copies the filenames to a 0-delimited string list (A\0B\0C\0\0)
2837 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
2839 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2840 UINT nStrCharCount = 0; /* index in src buffer */
2841 UINT nFileIndex = 0; /* index in dest buffer */
2842 UINT nFileCount = 0; /* number of files */
2843 UINT nStrLen = 0; /* length of string in edit control */
2844 LPWSTR lpstrEdit; /* buffer for string from edit control */
2846 TRACE("\n");
2848 /* get the filenames from the edit control */
2849 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
2850 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
2851 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
2853 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
2855 /* we might get single filename without any '"',
2856 * so we need nStrLen + terminating \0 + end-of-list \0 */
2857 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
2858 *sizeUsed = 0;
2860 /* build 0-delimited file list from filenames */
2861 while ( nStrCharCount <= nStrLen )
2863 if ( lpstrEdit[nStrCharCount]=='"' )
2865 nStrCharCount++;
2866 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
2868 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
2869 (*sizeUsed)++;
2870 nStrCharCount++;
2872 (*lpstrFileList)[nFileIndex++] = '\0';
2873 (*sizeUsed)++;
2874 nFileCount++;
2876 nStrCharCount++;
2879 /* single, unquoted string */
2880 if ((nStrLen > 0) && (*sizeUsed == 0) )
2882 strcpyW(*lpstrFileList, lpstrEdit);
2883 nFileIndex = strlenW(lpstrEdit) + 1;
2884 (*sizeUsed) = nFileIndex;
2885 nFileCount = 1;
2888 /* trailing \0 */
2889 (*lpstrFileList)[nFileIndex] = '\0';
2890 (*sizeUsed)++;
2892 MemFree(lpstrEdit);
2893 return nFileCount;
2896 #define SETDefFormatEtc(fe,cf,med) \
2898 (fe).cfFormat = cf;\
2899 (fe).dwAspect = DVASPECT_CONTENT; \
2900 (fe).ptd =NULL;\
2901 (fe).tymed = med;\
2902 (fe).lindex = -1;\
2906 * DATAOBJECT Helper functions
2909 /***********************************************************************
2910 * COMCTL32_ReleaseStgMedium
2912 * like ReleaseStgMedium from ole32
2914 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
2916 if(medium.pUnkForRelease)
2918 IUnknown_Release(medium.pUnkForRelease);
2920 else
2922 GlobalUnlock(medium.u.hGlobal);
2923 GlobalFree(medium.u.hGlobal);
2927 /***********************************************************************
2928 * GetPidlFromDataObject
2930 * Return pidl(s) by number from the cached DataObject
2932 * nPidlIndex=0 gets the fully qualified root path
2934 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
2937 STGMEDIUM medium;
2938 FORMATETC formatetc;
2939 LPITEMIDLIST pidl = NULL;
2941 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
2943 /* Set the FORMATETC structure*/
2944 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
2946 /* Get the pidls from IDataObject */
2947 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
2949 LPIDA cida = GlobalLock(medium.u.hGlobal);
2950 if(nPidlIndex <= cida->cidl)
2952 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
2954 COMCTL32_ReleaseStgMedium(medium);
2956 return pidl;
2959 /***********************************************************************
2960 * GetNumSelected
2962 * Return the number of selected items in the DataObject.
2965 UINT GetNumSelected( IDataObject *doSelected )
2967 UINT retVal = 0;
2968 STGMEDIUM medium;
2969 FORMATETC formatetc;
2971 TRACE("sv=%p\n", doSelected);
2973 if (!doSelected) return 0;
2975 /* Set the FORMATETC structure*/
2976 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
2978 /* Get the pidls from IDataObject */
2979 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
2981 LPIDA cida = GlobalLock(medium.u.hGlobal);
2982 retVal = cida->cidl;
2983 COMCTL32_ReleaseStgMedium(medium);
2984 return retVal;
2986 return 0;
2990 * TOOLS
2993 /***********************************************************************
2994 * GetName
2996 * Get the pidl's display name (relative to folder) and
2997 * put it in lpstrFileName.
2999 * Return NOERROR on success,
3000 * E_FAIL otherwise
3003 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3005 STRRET str;
3006 HRESULT hRes;
3008 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3010 if(!lpsf)
3012 HRESULT hRes;
3013 SHGetDesktopFolder(&lpsf);
3014 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3015 IShellFolder_Release(lpsf);
3016 return hRes;
3019 /* Get the display name of the pidl relative to the folder */
3020 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3022 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3024 return E_FAIL;
3027 /***********************************************************************
3028 * GetShellFolderFromPidl
3030 * pidlRel is the item pidl relative
3031 * Return the IShellFolder of the absolute pidl
3033 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3035 IShellFolder *psf = NULL,*psfParent;
3037 TRACE("%p\n", pidlAbs);
3039 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3041 psf = psfParent;
3042 if(pidlAbs && pidlAbs->mkid.cb)
3044 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3046 IShellFolder_Release(psfParent);
3047 return psf;
3050 /* return the desktop */
3051 return psfParent;
3053 return NULL;
3056 /***********************************************************************
3057 * GetParentPidl
3059 * Return the LPITEMIDLIST to the parent of the pidl in the list
3061 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3063 LPITEMIDLIST pidlParent;
3065 TRACE("%p\n", pidl);
3067 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3068 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3070 return pidlParent;
3073 /***********************************************************************
3074 * GetPidlFromName
3076 * returns the pidl of the file name relative to folder
3077 * NULL if an error occurred
3079 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3081 LPITEMIDLIST pidl = NULL;
3082 ULONG ulEaten;
3084 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3086 if(!lpcstrFileName) return NULL;
3087 if(!*lpcstrFileName) return NULL;
3089 if(!lpsf)
3091 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3092 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3093 IShellFolder_Release(lpsf);
3096 else
3098 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3100 return pidl;
3105 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPITEMIDLIST pidl)
3107 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3108 HRESULT ret;
3110 TRACE("%p, %p\n", psf, pidl);
3112 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3114 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3115 /* see documentation shell 4.1*/
3116 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3119 /***********************************************************************
3120 * BrowseSelectedFolder
3122 static BOOL BrowseSelectedFolder(HWND hwnd)
3124 BOOL bBrowseSelFolder = FALSE;
3125 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3127 TRACE("\n");
3129 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3131 LPITEMIDLIST pidlSelection;
3133 /* get the file selected */
3134 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3135 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3137 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3138 pidlSelection, SBSP_RELATIVE ) ) )
3140 WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3141 ' ','n','o','t',' ','e','x','i','s','t',0};
3142 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3145 bBrowseSelFolder = TRUE;
3147 COMDLG32_SHFree( pidlSelection );
3150 return bBrowseSelFolder;
3154 * Memory allocation methods */
3155 static void *MemAlloc(UINT size)
3157 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3160 static void MemFree(void *mem)
3162 if(mem)
3164 HeapFree(GetProcessHeap(),0,mem);