Fixed a memory leak in the file dialog.
[wine.git] / dlls / commdlg / filedlg95.c
blob9ddb27b20f79fb30ba2073f669a775b32706ae8f
1 /*
2 * COMMDLG - File Open Dialogs Win95 look and feel
4 */
5 #include <ctype.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include "winbase.h"
9 #include "ldt.h"
10 #include "heap.h"
11 #include "commdlg.h"
12 #include "dlgs.h"
13 #include "debugtools.h"
14 #include "cderr.h"
15 #include "tweak.h"
16 #include "winnls.h"
17 #include "shellapi.h"
18 #include "commctrl.h"
19 #include "tchar.h"
20 #include "filedlgbrowser.h"
21 #include "wine/undocshell.h"
22 #include "wine/obj_contextmenu.h"
24 DEFAULT_DEBUG_CHANNEL(commdlg)
26 #include "cdlg.h"
28 /***********************************************************************
29 * Data structure and global variables
31 typedef struct SFolder
33 int m_iImageIndex; /* Index of picture in image list */
34 HIMAGELIST hImgList;
35 int m_iIndent; /* Indentation index */
36 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
38 } SFOLDER,*LPSFOLDER;
40 typedef struct tagLookInInfo
42 int iMaxIndentation;
43 UINT uSelectedItem;
44 } LookInInfos;
47 /***********************************************************************
48 * Defines and global variables
51 /* Draw item constant */
52 #define ICONWIDTH 18
53 #define YTEXTOFFSET 2
54 #define XTEXTOFFSET 3
56 /* AddItem flags*/
57 #define LISTEND -1
59 /* SearchItem methods */
60 #define SEARCH_PIDL 1
61 #define SEARCH_EXP 2
62 #define ITEM_NOTFOUND -1
64 /* Undefined windows message sent by CreateViewObject*/
65 #define WM_GETISHELLBROWSER WM_USER+7
67 /* NOTE
68 * Those macros exist in windowsx.h. However, you can't really use them since
69 * they rely on the UNICODE defines and can't be use inside Wine itself.
72 /* Combo box macros */
73 #define CBAddString(hwnd,str) \
74 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
76 #define CBInsertString(hwnd,str,pos) \
77 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
79 #define CBDeleteString(hwnd,pos) \
80 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
82 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
83 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
85 #define CBGetItemDataPtr(hwnd,iItemId) \
86 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
88 #define CBGetLBText(hwnd,iItemId,str) \
89 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
91 #define CBGetCurSel(hwnd) \
92 SendMessageA(hwnd,CB_GETCURSEL,0,0);
94 #define CBSetCurSel(hwnd,pos) \
95 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
97 #define CBGetCount(hwnd) \
98 SendMessageA(hwnd,CB_GETCOUNT,0,0);
99 #define CBShowDropDown(hwnd,show) \
100 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
103 const char *FileOpenDlgInfosStr = "FileOpenDlgInfos"; /* windows property description string */
104 const char *LookInInfosStr = "LookInInfos"; /* LOOKIN combo box property */
106 static const char defaultFilter[] = "*.*";
108 /***********************************************************************
109 * Prototypes
112 /* Internal functions used by the dialog */
113 static LRESULT FILEDLG95_OnWMInitDialog(HWND hwnd, WPARAM wParam, LPARAM lParam);
114 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
115 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
116 BOOL FILEDLG95_OnOpen(HWND hwnd);
117 static LRESULT FILEDLG95_InitUI(HWND hwnd);
118 static void FILEDLG95_Clean(HWND hwnd);
120 /* Functions used by the shell object */
121 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
122 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
123 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
124 static BOOL FILEDLG95_SHELL_NewFolder(HWND hwnd);
125 BOOL FILEDLG95_SHELL_FillIncludedItemList(HWND hwnd,
126 LPITEMIDLIST pidlCurrentFolder,
127 LPSTR lpstrMask);
128 static void FILEDLG95_SHELL_Clean(HWND hwnd);
129 /* Functions used by the filetype combo box */
130 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
131 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
132 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPSTR lpstrExt);
133 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
135 /* Functions used by the Look In combo box */
136 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo);
137 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
138 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
139 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
140 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
141 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
142 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
143 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
144 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
146 /* Miscellaneous tool functions */
147 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
148 HRESULT GetFileName(HWND hwnd, LPITEMIDLIST pidl, LPSTR lpstrFileName);
149 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
150 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
151 LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPCSTR lpcstrFileName);
153 /* Shell memory allocation */
154 void *MemAlloc(UINT size);
155 void MemFree(void *mem);
157 BOOL WINAPI GetOpenFileName95(FileOpenDlgInfos *fodInfos);
158 BOOL WINAPI GetSaveFileName95(FileOpenDlgInfos *fodInfos);
159 HRESULT WINAPI FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
161 /***********************************************************************
162 * GetOpenFileName95
164 * Creates an Open common dialog box that lets the user select
165 * the drive, directory, and the name of a file or set of files to open.
167 * IN : The FileOpenDlgInfos structure associated with the dialog
168 * OUT : TRUE on success
169 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
171 BOOL WINAPI GetOpenFileName95(FileOpenDlgInfos *fodInfos)
174 LRESULT lRes;
175 LPCVOID template;
176 HRSRC hRes;
177 HANDLE hDlgTmpl = 0;
179 /* Create the dialog from a template */
181 if (fodInfos->ofnInfos.Flags & OFN_ENABLETEMPLATEHANDLE)
183 if (!(template = LockResource( MapHModuleSL(fodInfos->ofnInfos.hInstance ))))
185 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
186 return FALSE;
189 else if (fodInfos->ofnInfos.Flags & OFN_ENABLETEMPLATE)
191 if (!(hRes = FindResourceA(MapHModuleSL(fodInfos->ofnInfos.hInstance),
192 (fodInfos->ofnInfos.lpTemplateName), RT_DIALOGA)))
194 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
195 return FALSE;
197 if (!(hDlgTmpl = LoadResource( MapHModuleSL(fodInfos->ofnInfos.hInstance),
198 hRes )) ||
199 !(template = LockResource( hDlgTmpl )))
201 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
202 return FALSE;
205 else
207 if(!(hRes = FindResourceA(COMMDLG_hInstance32,MAKEINTRESOURCEA(IDD_OPENDIALOG),RT_DIALOGA)))
209 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
210 return FALSE;
212 if (!(hDlgTmpl = LoadResource(COMMDLG_hInstance32, hRes )) ||
213 !(template = LockResource( hDlgTmpl )))
215 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
216 return FALSE;
220 lRes = DialogBoxIndirectParamA(COMMDLG_hInstance32,
221 (LPDLGTEMPLATEA) template,
222 fodInfos->ofnInfos.hwndOwner,
223 (DLGPROC) FileOpenDlgProc95,
224 (LPARAM) fodInfos);
226 /* Unable to create the dialog*/
227 if( lRes == -1)
228 return FALSE;
230 return lRes;
233 /***********************************************************************
234 * GetSaveFileName95
236 * Creates an Save as common dialog box that lets the user select
237 * the drive, directory, and the name of a file or set of files to open.
239 * IN : The FileOpenDlgInfos structure associated with the dialog
240 * OUT : TRUE on success
241 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
243 BOOL WINAPI GetSaveFileName95(FileOpenDlgInfos *fodInfos)
246 LRESULT lRes;
247 LPCVOID template;
248 HRSRC hRes;
249 HANDLE hDlgTmpl = 0;
251 /* Create the dialog from a template */
253 if (fodInfos->ofnInfos.Flags & OFN_ENABLETEMPLATEHANDLE)
255 if (!(template = LockResource( MapHModuleSL(fodInfos->ofnInfos.hInstance ))))
257 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
258 return FALSE;
261 else if (fodInfos->ofnInfos.Flags & OFN_ENABLETEMPLATE)
263 if (!(hRes = FindResourceA(MapHModuleSL(fodInfos->ofnInfos.hInstance),
264 (fodInfos->ofnInfos.lpTemplateName), RT_DIALOGA)))
266 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
267 return FALSE;
269 if (!(hDlgTmpl = LoadResource( MapHModuleSL(fodInfos->ofnInfos.hInstance),
270 hRes )) ||
271 !(template = LockResource( hDlgTmpl )))
273 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
274 return FALSE;
277 else
279 if(!(hRes = FindResourceA(COMMDLG_hInstance32,MAKEINTRESOURCEA(IDD_SAVEDIALOG),RT_DIALOGA)))
281 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
282 return FALSE;
284 if (!(hDlgTmpl = LoadResource(COMMDLG_hInstance32, hRes )) ||
285 !(template = LockResource( hDlgTmpl )))
287 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
288 return FALSE;
291 lRes = DialogBoxIndirectParamA(COMMDLG_hInstance32,
292 (LPDLGTEMPLATEA) template,
293 fodInfos->ofnInfos.hwndOwner,
294 (DLGPROC) FileOpenDlgProc95,
295 (LPARAM) fodInfos);
296 /* Unable to create the dialog*/
297 if( lRes == -1)
298 return FALSE;
300 return lRes;
303 /***********************************************************************
304 * GetFileDialog95A
306 * Copy the OPENFILENAMEA structure in a FileOpenDlgInfos structure.
307 * Call GetOpenFileName95 with this structure and clean the memory.
309 * IN : The OPENFILENAMEA initialisation structure passed to
310 * GetOpenFileNameA win api function (see filedlg.c)
312 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
315 BOOL ret;
316 FileOpenDlgInfos *fodInfos;
318 /* Initialise FileOpenDlgInfos structure*/
319 fodInfos = (FileOpenDlgInfos*)MemAlloc(sizeof(FileOpenDlgInfos));
320 memset(&fodInfos->ofnInfos,'\0',sizeof(*ofn)); fodInfos->ofnInfos.lStructSize = sizeof(*ofn);
321 fodInfos->ofnInfos.hwndOwner = ofn->hwndOwner;
322 fodInfos->ofnInfos.hInstance = MapHModuleLS(ofn->hInstance);
323 if (ofn->lpstrFilter)
325 LPSTR s,x;
327 /* filter is a list... title\0ext\0......\0\0 */
328 s = (LPSTR)ofn->lpstrFilter;
329 while (*s)
330 s = s+strlen(s)+1;
331 s++;
332 x = (LPSTR)MemAlloc(s-ofn->lpstrFilter);
333 memcpy(x,ofn->lpstrFilter,s-ofn->lpstrFilter);
334 fodInfos->ofnInfos.lpstrFilter = (LPSTR)x;
336 if (ofn->lpstrCustomFilter)
338 LPSTR s,x;
340 /* filter is a list... title\0ext\0......\0\0 */
341 s = (LPSTR)ofn->lpstrCustomFilter;
342 while (*s)
343 s = s+strlen(s)+1;
344 s++;
345 x = MemAlloc(s-ofn->lpstrCustomFilter);
346 memcpy(x,ofn->lpstrCustomFilter,s-ofn->lpstrCustomFilter);
347 fodInfos->ofnInfos.lpstrCustomFilter = (LPSTR)x;
349 fodInfos->ofnInfos.nMaxCustFilter = ofn->nMaxCustFilter;
350 if(ofn->nFilterIndex)
351 fodInfos->ofnInfos.nFilterIndex = --ofn->nFilterIndex;
352 if (ofn->nMaxFile)
354 fodInfos->ofnInfos.lpstrFile = (LPSTR)MemAlloc(ofn->nMaxFile);
355 strcpy((LPSTR)fodInfos->ofnInfos.lpstrFile,ofn->lpstrFile);
357 fodInfos->ofnInfos.nMaxFile = ofn->nMaxFile;
358 fodInfos->ofnInfos.nMaxFileTitle = ofn->nMaxFileTitle;
359 if (fodInfos->ofnInfos.nMaxFileTitle)
360 fodInfos->ofnInfos.lpstrFileTitle = (LPSTR)MemAlloc(ofn->nMaxFileTitle);
361 if (ofn->lpstrInitialDir)
363 fodInfos->ofnInfos.lpstrInitialDir = (LPSTR)MemAlloc(strlen(ofn->lpstrInitialDir));
364 strcpy((LPSTR)fodInfos->ofnInfos.lpstrInitialDir,ofn->lpstrInitialDir);
367 if (ofn->lpstrTitle)
369 fodInfos->ofnInfos.lpstrTitle = (LPSTR)MemAlloc(strlen(ofn->lpstrTitle));
370 strcpy((LPSTR)fodInfos->ofnInfos.lpstrTitle,ofn->lpstrTitle);
373 fodInfos->ofnInfos.Flags = ofn->Flags|OFN_WINE;
374 fodInfos->ofnInfos.nFileOffset = ofn->nFileOffset;
375 fodInfos->ofnInfos.nFileExtension = ofn->nFileExtension;
376 if (ofn->lpstrDefExt)
378 fodInfos->ofnInfos.lpstrDefExt = MemAlloc(strlen(ofn->lpstrDefExt));
379 strcpy((LPSTR)fodInfos->ofnInfos.lpstrDefExt,ofn->lpstrDefExt);
381 fodInfos->ofnInfos.lCustData = ofn->lCustData;
382 fodInfos->ofnInfos.lpfnHook = (LPOFNHOOKPROC)ofn->lpfnHook;
384 if (ofn->lpTemplateName)
386 /* template don't work - using normal dialog */
387 /* fodInfos->ofnInfos.lpTemplateName = MemAlloc(strlen(ofn->lpTemplateName));
388 strcpy((LPSTR)fodInfos->ofnInfos.lpTemplateName,ofn->lpTemplateName);*/
389 fodInfos->ofnInfos.Flags &= ~OFN_ENABLETEMPLATEHANDLE;
390 fodInfos->ofnInfos.Flags &= ~OFN_ENABLETEMPLATE;
391 FIXME("File dialog 95 template not implemented\n");
395 /* Replace the NULL lpstrInitialDir by the current folder */
396 if(!ofn->lpstrInitialDir)
398 fodInfos->ofnInfos.lpstrInitialDir = MemAlloc(MAX_PATH);
399 GetCurrentDirectoryA(MAX_PATH,(LPSTR)fodInfos->ofnInfos.lpstrInitialDir);
402 switch(iDlgType)
404 case OPEN_DIALOG :
405 ret = GetOpenFileName95(fodInfos);
406 break;
407 case SAVE_DIALOG :
408 ret = GetSaveFileName95(fodInfos);
409 break;
410 default :
411 ret = 0;
414 ofn->nFileOffset = fodInfos->ofnInfos.nFileOffset;
415 ofn->nFileExtension = fodInfos->ofnInfos.nFileExtension;
416 if (fodInfos->ofnInfos.lpstrFilter)
417 MemFree((LPVOID)(fodInfos->ofnInfos.lpstrFilter));
418 if (fodInfos->ofnInfos.lpTemplateName)
419 MemFree((LPVOID)(fodInfos->ofnInfos.lpTemplateName));
420 if (fodInfos->ofnInfos.lpstrDefExt)
421 MemFree((LPVOID)(fodInfos->ofnInfos.lpstrDefExt));
422 if (fodInfos->ofnInfos.lpstrTitle)
423 MemFree((LPVOID)(fodInfos->ofnInfos.lpstrTitle));
424 if (fodInfos->ofnInfos.lpstrInitialDir)
425 MemFree((LPVOID)(fodInfos->ofnInfos.lpstrInitialDir));
426 if (fodInfos->ofnInfos.lpstrCustomFilter)
427 MemFree((LPVOID)(fodInfos->ofnInfos.lpstrCustomFilter));
429 if (fodInfos->ofnInfos.lpstrFile)
431 strcpy(ofn->lpstrFile,fodInfos->ofnInfos.lpstrFile);
432 MemFree((LPVOID)fodInfos->ofnInfos.lpstrFile);
434 if (fodInfos->ofnInfos.lpstrFileTitle)
436 if (ofn->lpstrFileTitle)
437 strcpy(ofn->lpstrFileTitle,
438 fodInfos->ofnInfos.lpstrFileTitle);
439 MemFree((LPVOID)fodInfos->ofnInfos.lpstrFileTitle);
442 MemFree((LPVOID)(fodInfos));
443 return ret;
446 /***********************************************************************
447 * GetFileDialog95W
449 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
450 * Call GetOpenFileName95 with this structure and clean the memory.
452 * IN : The OPENFILENAMEW initialisation structure passed to
453 * GetOpenFileNameW win api function (see filedlg.c)
455 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
457 BOOL ret;
458 FileOpenDlgInfos *fodInfos;
460 /* Initialise FileOpenDlgInfos structure*/
461 fodInfos = (FileOpenDlgInfos*)MemAlloc(sizeof(FileOpenDlgInfos));
462 memset(&fodInfos->ofnInfos,'\0',sizeof(*ofn));
463 fodInfos->ofnInfos.lStructSize = sizeof(*ofn);
464 fodInfos->ofnInfos.hwndOwner = ofn->hwndOwner;
465 fodInfos->ofnInfos.hInstance = MapHModuleLS(ofn->hInstance);
466 if (ofn->lpstrFilter)
468 LPWSTR s;
469 LPSTR x,y;
470 int n;
472 /* filter is a list... title\0ext\0......\0\0 */
473 s = (LPWSTR)ofn->lpstrFilter;
475 while (*s)
476 s = s+lstrlenW(s)+1;
477 s++;
478 n = s - ofn->lpstrFilter; /* already divides by 2. ptr magic */
479 x = y = (LPSTR)MemAlloc(n);
480 s = (LPWSTR)ofn->lpstrFilter;
481 while (*s) {
482 lstrcpyWtoA(x,s);
483 x+=lstrlenA(x)+1;
484 s+=lstrlenW(s)+1;
486 *x=0;
487 fodInfos->ofnInfos.lpstrFilter = (LPSTR)y;
489 if (ofn->lpstrCustomFilter) {
490 LPWSTR s;
491 LPSTR x,y;
492 int n;
494 /* filter is a list... title\0ext\0......\0\0 */
495 s = (LPWSTR)ofn->lpstrCustomFilter;
496 while (*s)
497 s = s+lstrlenW(s)+1;
498 s++;
499 n = s - ofn->lpstrCustomFilter;
500 x = y = (LPSTR)MemAlloc(n);
501 s = (LPWSTR)ofn->lpstrCustomFilter;
502 while (*s) {
503 lstrcpyWtoA(x,s);
504 x+=lstrlenA(x)+1;
505 s+=lstrlenW(s)+1;
507 *x=0;
508 fodInfos->ofnInfos.lpstrCustomFilter = (LPSTR)y;
510 fodInfos->ofnInfos.nMaxCustFilter = ofn->nMaxCustFilter;
511 fodInfos->ofnInfos.nFilterIndex = ofn->nFilterIndex;
512 if (ofn->nMaxFile)
513 fodInfos->ofnInfos.lpstrFile = (LPSTR)MemAlloc(ofn->nMaxFile);
514 fodInfos->ofnInfos.nMaxFile = ofn->nMaxFile;
515 fodInfos->ofnInfos.nMaxFileTitle = ofn->nMaxFileTitle;
516 if (ofn->nMaxFileTitle)
517 fodInfos->ofnInfos.lpstrFileTitle = (LPSTR)MemAlloc(ofn->nMaxFileTitle);
518 if (ofn->lpstrInitialDir)
519 fodInfos->ofnInfos.lpstrInitialDir = (LPSTR)MemAlloc(lstrlenW(ofn->lpstrInitialDir));
520 if (ofn->lpstrTitle)
521 fodInfos->ofnInfos.lpstrTitle = (LPSTR)MemAlloc(lstrlenW(ofn->lpstrTitle));
522 fodInfos->ofnInfos.Flags = ofn->Flags|OFN_WINE|OFN_UNICODE;
523 fodInfos->ofnInfos.nFileOffset = ofn->nFileOffset;
524 fodInfos->ofnInfos.nFileExtension = ofn->nFileExtension;
525 if (ofn->lpstrDefExt)
526 fodInfos->ofnInfos.lpstrDefExt = (LPSTR)MemAlloc(lstrlenW(ofn->lpstrDefExt));
527 fodInfos->ofnInfos.lCustData = ofn->lCustData;
528 fodInfos->ofnInfos.lpfnHook = (LPOFNHOOKPROC)ofn->lpfnHook;
529 if (ofn->lpTemplateName)
530 fodInfos->ofnInfos.lpTemplateName = (LPSTR)MemAlloc(lstrlenW(ofn->lpTemplateName));
531 switch(iDlgType)
533 case OPEN_DIALOG :
534 ret = GetOpenFileName95(fodInfos);
535 break;
536 case SAVE_DIALOG :
537 ret = GetSaveFileName95(fodInfos);
538 break;
539 default :
540 ret = 0;
544 /* Cleaning */
545 ofn->nFileOffset = fodInfos->ofnInfos.nFileOffset;
546 ofn->nFileExtension = fodInfos->ofnInfos.nFileExtension;
547 if (fodInfos->ofnInfos.lpstrFilter)
548 MemFree((LPVOID)(fodInfos->ofnInfos.lpstrFilter));
549 if (fodInfos->ofnInfos.lpTemplateName)
550 MemFree((LPVOID)(fodInfos->ofnInfos.lpTemplateName));
551 if (fodInfos->ofnInfos.lpstrDefExt)
552 MemFree((LPVOID)(fodInfos->ofnInfos.lpstrDefExt));
553 if (fodInfos->ofnInfos.lpstrTitle)
554 MemFree((LPVOID)(fodInfos->ofnInfos.lpstrTitle));
555 if (fodInfos->ofnInfos.lpstrInitialDir)
556 MemFree((LPVOID)(fodInfos->ofnInfos.lpstrInitialDir));
557 if (fodInfos->ofnInfos.lpstrCustomFilter)
558 MemFree((LPVOID)(fodInfos->ofnInfos.lpstrCustomFilter));
560 if (fodInfos->ofnInfos.lpstrFile) {
561 lstrcpyAtoW(ofn->lpstrFile,(fodInfos->ofnInfos.lpstrFile));
562 MemFree((LPVOID)(fodInfos->ofnInfos.lpstrFile));
565 if (fodInfos->ofnInfos.lpstrFileTitle) {
566 if (ofn->lpstrFileTitle)
567 lstrcpyAtoW(ofn->lpstrFileTitle,
568 (fodInfos->ofnInfos.lpstrFileTitle));
569 MemFree((LPVOID)(fodInfos->ofnInfos.lpstrFileTitle));
571 MemFree((LPVOID)(fodInfos));
572 return ret;
577 /***********************************************************************
578 * FileOpenDlgProc95
580 * File open dialog procedure
582 HRESULT WINAPI FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
585 switch(uMsg)
587 case WM_INITDIALOG :
588 return FILEDLG95_OnWMInitDialog(hwnd, wParam, lParam);
589 case WM_COMMAND:
590 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
591 case WM_DRAWITEM:
593 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
595 case IDC_LOOKIN:
596 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
597 return TRUE;
600 return FALSE;
602 case WM_GETISHELLBROWSER:
603 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
605 case WM_DESTROY:
606 RemovePropA(hwnd, FileOpenDlgInfosStr);
607 default :
608 return FALSE;
612 /***********************************************************************
613 * FILEDLG95_OnWMInitDialog
615 * WM_INITDIALOG message handler
617 static LRESULT FILEDLG95_OnWMInitDialog(HWND hwnd, WPARAM wParam, LPARAM lParam)
619 LPITEMIDLIST pidlItemId;
620 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
622 TRACE("\n");
624 /* Adds the FileOpenDlgInfos in the property list of the dialog
625 so it will be easily accessible through a GetPropA(...) */
626 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
628 /* Make sure the common control DLL is loaded */
629 InitCommonControls();
631 /* Initialise shell objects */
632 FILEDLG95_SHELL_Init(hwnd);
634 /* Initialise dialog UI */
635 FILEDLG95_InitUI(hwnd);
637 /* Initialize the Look In combo box*/
638 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
640 /* Initialize the filter combo box */
641 FILEDLG95_FILETYPE_Init(hwnd);
643 /* Get the initial directory pidl */
645 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->ofnInfos.lpstrInitialDir)))
647 char path[MAX_PATH];
649 GetCurrentDirectoryA(MAX_PATH,path);
650 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,
651 path);
655 /* Browse to the initial directory */
656 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId,SBSP_RELATIVE);
658 /* Free pidlItem memory */
659 SHFree(pidlItemId);
661 return TRUE;
663 /***********************************************************************
664 * FILEDLG95_Clean
666 * Regroups all the cleaning functions of the filedlg
668 void FILEDLG95_Clean(HWND hwnd)
670 FILEDLG95_FILETYPE_Clean(hwnd);
671 FILEDLG95_LOOKIN_Clean(hwnd);
672 FILEDLG95_SHELL_Clean(hwnd);
674 /***********************************************************************
675 * FILEDLG95_OnWMCommand
677 * WM_COMMAND message handler
679 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
681 WORD wNotifyCode = HIWORD(wParam); // notification code
682 WORD wID = LOWORD(wParam); // item, control, or accelerator identifier
684 switch(wID)
686 /* OK button */
687 case IDOK:
688 FILEDLG95_OnOpen(hwnd);
689 break;
690 /* Cancel button */
691 case IDCANCEL:
692 FILEDLG95_Clean(hwnd);
693 EndDialog(hwnd, FALSE);
694 break;
695 /* Filetype combo box */
696 case IDC_FILETYPE:
697 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
698 break;
699 /* LookIn combo box */
700 case IDC_LOOKIN:
701 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
702 break;
703 /* Up folder button */
704 case IDC_UPFOLDER:
705 FILEDLG95_SHELL_UpFolder(hwnd);
706 break;
707 /* List option button */
708 case IDC_LIST:
709 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLIST);
710 break;
711 /* Details option button */
712 case IDC_DETAILS:
713 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILS);
714 break;
715 /* New folder button */
716 case IDC_NEWFOLDER:
717 FILEDLG95_SHELL_NewFolder(hwnd);
718 break;
720 case IDC_FILENAME:
721 break;
725 return 0;
728 /***********************************************************************
729 * FILEDLG95_OnWMGetIShellBrowser
731 * WM_GETISHELLBROWSER message handler
733 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
736 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
738 TRACE("\n");
740 SetWindowLongA(hwnd,DWL_MSGRESULT,(LONG)fodInfos->Shell.FOIShellBrowser);
742 return TRUE;
746 /***********************************************************************
747 * FILEDLG95_InitUI
750 static LRESULT FILEDLG95_InitUI(HWND hwnd)
752 HIMAGELIST himlToolbar;
753 HICON hicon;
754 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
756 TRACE("%p\n", fodInfos);
758 /* Get the hwnd of the controls */
759 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
760 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
761 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
763 ShowWindow(GetDlgItem(hwnd,IDC_SHELLSTATIC),SW_HIDE);
764 /* Load the icons bitmaps */
766 if((himlToolbar = COMDLG32_ImageList_LoadImageA(COMMDLG_hInstance32,
767 MAKEINTRESOURCEA(IDB_TOOLBAR),
770 CLR_DEFAULT,
771 IMAGE_BITMAP,
772 0)))
774 /* Up folder icon */
775 if((hicon = COMDLG32_ImageList_GetIcon(himlToolbar,0,ILD_NORMAL)))
776 SendDlgItemMessageA(hwnd,IDC_UPFOLDER,BM_SETIMAGE,(WPARAM)IMAGE_ICON,(LPARAM)hicon);
777 /* New folder icon */
778 if((hicon = COMDLG32_ImageList_GetIcon(himlToolbar,1,ILD_NORMAL)))
779 SendDlgItemMessageA(hwnd,IDC_NEWFOLDER,BM_SETIMAGE,(WPARAM)IMAGE_ICON,(LPARAM)hicon);
780 /* List view icon */
781 if((hicon = COMDLG32_ImageList_GetIcon(himlToolbar,2,ILD_NORMAL)))
782 SendDlgItemMessageA(hwnd,IDC_LIST,BM_SETIMAGE,(WPARAM)IMAGE_ICON,(LPARAM)hicon);
783 /* Detail view icon */
784 if((hicon = COMDLG32_ImageList_GetIcon(himlToolbar,3,ILD_NORMAL)))
785 SendDlgItemMessageA(hwnd,IDC_DETAILS,BM_SETIMAGE,(WPARAM)IMAGE_ICON,(LPARAM)hicon);
786 /* Cleanup */
787 COMDLG32_ImageList_Destroy(himlToolbar);
792 /* Set the window text with the text specified in the OPENFILENAME structure */
793 if(fodInfos->ofnInfos.lpstrTitle)
794 SetWindowTextA(hwnd,fodInfos->ofnInfos.lpstrTitle);
796 /* Initialise the file name edit control */
797 if(strlen(fodInfos->ofnInfos.lpstrFile))
799 SetDlgItemTextA(hwnd,IDC_FILENAME,fodInfos->ofnInfos.lpstrFile);
801 /* Must the open as read only check box be checked ?*/
802 if(fodInfos->ofnInfos.Flags & OFN_READONLY)
804 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
806 /* Must the open as read only check box be hid ?*/
807 if(fodInfos->ofnInfos.Flags & OFN_HIDEREADONLY)
809 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
812 return 0;
815 /***********************************************************************
816 * FILEDLG95_OnOpen
818 * Ok button WM_COMMAND message handler
820 * If the function succeeds, the return value is nonzero.
822 BOOL FILEDLG95_OnOpen(HWND hwnd)
824 char lpstrFileName[MAX_PATH];
825 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
827 TRACE("\n");
829 if(GetDlgItemTextA(hwnd,IDC_FILENAME,lpstrFileName,MAX_PATH))
831 char *tmp;
832 char lpstrFile[MAX_PATH];
834 /* Get the selected file name and path */
835 SHGetPathFromIDListA(fodInfos->ShellInfos.pidlAbsCurrent,
836 lpstrFile);
837 if(strcmp(&lpstrFile[strlen(lpstrFile)-1],"\\"))
838 strcat(lpstrFile,"\\");
839 strcat(lpstrFile,lpstrFileName);
841 /* Check if this is a search */
842 if(strchr(lpstrFileName,'*') || strchr(lpstrFileName,'?'))
844 int iPos;
846 /* Set the current filter with the current selection */
847 if(fodInfos->ShellInfos.lpstrCurrentFilter)
848 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
850 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc((strlen(lpstrFileName)+1)*2);
851 lstrcpyAtoW(fodInfos->ShellInfos.lpstrCurrentFilter,(LPSTR)strlwr((LPSTR)lpstrFileName));
854 IShellView_Refresh(fodInfos->Shell.FOIShellView);
856 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB,lpstrFileName)))
857 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
859 return FALSE;
862 /* Check file extension */
864 if(!strrchr(lpstrFile,'.'))
866 /* if the file has no extension, append the selected
867 extension of the filetype combo box */
868 int iExt;
869 LPSTR lpstrExt;
870 LPSTR lpstrTmp;
871 iExt = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
872 lpstrTmp = (LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iExt);
874 if((lpstrExt = strchr(lpstrTmp,';')))
876 int i = lpstrExt - lpstrTmp;
877 lpstrExt = MemAlloc(i);
878 strncpy(lpstrExt,&lpstrTmp[1],i-1);
880 else
882 lpstrExt = MemAlloc(strlen(lpstrTmp)-1);
883 strcpy(lpstrExt,&lpstrTmp[1]);
886 if(!strcmp(&lpstrExt[1],"*") && fodInfos->ofnInfos.lpstrDefExt)
888 lpstrExt = MemAlloc(strlen(fodInfos->ofnInfos.lpstrDefExt)+1);
889 strcat(lpstrExt,".");
890 strcat(lpstrExt,(LPSTR) fodInfos->ofnInfos.lpstrDefExt);
893 strcat(lpstrFile,lpstrExt);
895 /* Check if the selected file exist */
897 if(strlen(lpstrFile) > fodInfos->ofnInfos.nMaxFile)
899 /* set error FNERR_BUFFERTOSMALL */
900 FILEDLG95_Clean(hwnd);
901 return EndDialog(hwnd,FALSE);
903 strcpy(fodInfos->ofnInfos.lpstrFile,lpstrFile);
905 /* Set the lpstrFileTitle of the OPENFILENAME structure */
906 if(fodInfos->ofnInfos.lpstrFileTitle)
907 strncpy(fodInfos->ofnInfos.lpstrFileTitle,
908 lpstrFileName,
909 fodInfos->ofnInfos.nMaxFileTitle);
911 /* Check if the file is to be opened as read only */
912 if(BST_CHECKED == SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_GETSTATE,0,0))
913 SetFileAttributesA(fodInfos->ofnInfos.lpstrFile,FILE_ATTRIBUTE_READONLY);
915 /* nFileExtension and nFileOffset of OPENFILENAME structure */
916 tmp = strrchr(fodInfos->ofnInfos.lpstrFile,'\\');
917 fodInfos->ofnInfos.nFileOffset = tmp - fodInfos->ofnInfos.lpstrFile + 1;
918 tmp = strrchr(fodInfos->ofnInfos.lpstrFile,'.');
919 fodInfos->ofnInfos.nFileExtension = tmp - fodInfos->ofnInfos.lpstrFile + 1;
921 /* Check if selected file exists */
922 if(!GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrFileName))
924 /* Tell the user the selected does not exist */
925 if(fodInfos->ofnInfos.Flags & OFN_FILEMUSTEXIST)
927 char lpstrNotFound[100];
928 char lpstrMsg[100];
929 char tmp[400];
931 LoadStringA(COMMDLG_hInstance32,IDS_FILENOTFOUND,lpstrNotFound,100);
932 LoadStringA(COMMDLG_hInstance32,IDS_VERIFYFILE,lpstrMsg,100);
934 strcpy(tmp,fodInfos->ofnInfos.lpstrFile);
935 strcat(tmp,"\n");
936 strcat(tmp,lpstrNotFound);
937 strcat(tmp,"\n");
938 strcat(tmp,lpstrMsg);
940 MessageBoxA(hwnd,tmp,fodInfos->ofnInfos.lpstrTitle,MB_OK | MB_ICONEXCLAMATION);
941 return FALSE;
943 /* Ask the user if he wants to create the file*/
944 if(fodInfos->ofnInfos.Flags & OFN_CREATEPROMPT)
946 char tmp[100];
948 LoadStringA(COMMDLG_hInstance32,IDS_CREATEFILE,tmp,100);
950 if(IDYES == MessageBoxA(hwnd,tmp,fodInfos->ofnInfos.lpstrTitle,MB_YESNO | MB_ICONQUESTION))
952 /* Create the file, clean and exit */
953 FILEDLG95_Clean(hwnd);
954 return EndDialog(hwnd,TRUE);
956 return FALSE;
959 /* clean and exit */
960 FILEDLG95_Clean(hwnd);
961 return EndDialog(hwnd,TRUE);
964 return FALSE;
967 /***********************************************************************
968 * FILEDLG95_SHELL_Init
970 * Initialisation of the shell objects
972 static HRESULT FILEDLG95_SHELL_Init(HWND hwnd)
974 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
976 TRACE("\n");
979 * Initialisation of the FileOpenDialogInfos structure
982 /* Shell */
984 fodInfos->Shell.FOIShellView = NULL;
985 if(FAILED(SHGetDesktopFolder(&fodInfos->Shell.FOIShellFolder)))
986 return E_FAIL;
988 /*ShellInfos */
989 fodInfos->ShellInfos.hwndOwner = hwnd;
991 fodInfos->ShellInfos.folderSettings.fFlags = FWF_AUTOARRANGE | FWF_ALIGNLEFT;
992 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
994 GetWindowRect(GetDlgItem(hwnd,IDC_SHELLSTATIC),&fodInfos->ShellInfos.rectView);
995 ScreenToClient(hwnd,(LPPOINT)&fodInfos->ShellInfos.rectView.left);
996 ScreenToClient(hwnd,(LPPOINT)&fodInfos->ShellInfos.rectView.right);
998 /* Construct the IShellBrowser interface */
999 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
1001 return NOERROR;
1004 /***********************************************************************
1005 * FILEDLG95_SHELL_ExecuteCommand
1007 * Change the folder option and refresh the view
1008 * If the function succeeds, the return value is nonzero.
1010 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
1012 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1014 IContextMenu * pcm;
1015 CMINVOKECOMMANDINFO ci;
1016 TRACE("\n");
1018 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
1019 SVGIO_BACKGROUND,
1020 &IID_IContextMenu,
1021 (LPVOID*)&pcm)))
1023 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
1024 ci.lpVerb = lpVerb;
1025 ci.hwnd = hwnd;
1027 IContextMenu_InvokeCommand(pcm, &ci);
1028 IContextMenu_Release(pcm);
1031 return FALSE;
1034 /***********************************************************************
1035 * FILEDLG95_SHELL_UpFolder
1037 * Browse to the specified object
1038 * If the function succeeds, the return value is nonzero.
1040 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
1042 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1044 TRACE("\n");
1046 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
1047 NULL,
1048 SBSP_PARENT)))
1050 return TRUE;
1052 return FALSE;
1055 /***********************************************************************
1056 * FILEDLG95_SHELL_NewFolder
1058 * Creates a new directory with New folder as name
1059 * If the function succeeds, the return value is nonzero.
1060 * FIXME: let the contextmenu (CMDSTR_NEWFOLDER) do this thing
1062 static BOOL FILEDLG95_SHELL_NewFolder(HWND hwnd)
1064 char lpstrDirName[MAX_PATH] = "New folder";
1065 BOOL bRes;
1066 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1068 TRACE("\n");
1070 if((bRes = CreateDirectoryA(lpstrDirName,NULL)))
1072 LPITEMIDLIST pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder,lpstrDirName);
1073 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1074 IShellView_SelectItem(fodInfos->Shell.FOIShellView,
1075 pidl,
1076 (SVSI_DESELECTOTHERS | SVSI_EDIT | SVSI_ENSUREVISIBLE
1077 |SVSI_FOCUSED|SVSI_SELECT));
1082 return bRes;
1085 /***********************************************************************
1086 * FILEDLG95_SHELL_Clean
1088 * Cleans the memory used by shell objects
1090 static void FILEDLG95_SHELL_Clean(HWND hwnd)
1092 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1094 TRACE("\n");
1096 /* clean Shell interfaces */
1097 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
1098 IShellView_Release(fodInfos->Shell.FOIShellView);
1099 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
1100 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
1103 /***********************************************************************
1104 * FILEDLG95_FILETYPE_Init
1106 * Initialisation of the file type combo box
1108 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
1110 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1112 TRACE("\n");
1114 if(fodInfos->ofnInfos.lpstrFilter)
1116 int iStrIndex = 0;
1117 int iPos = 0;
1118 LPSTR lpstrFilter;
1119 LPSTR lpstrTmp;
1121 for(;;)
1123 /* filter is a list... title\0ext\0......\0\0 */
1124 /* Set the combo item text to the title and the item data
1125 to the ext */
1126 char *lpstrExt = NULL;
1127 LPSTR lpstrExtTmp = NULL;
1128 /* Get the title */
1129 lpstrTmp = (&((LPBYTE)fodInfos->ofnInfos.lpstrFilter)[iStrIndex]);
1130 if(!strlen(lpstrTmp))
1131 break;
1132 iStrIndex += strlen(lpstrTmp) +1;
1133 /* Get the extension */
1134 lpstrExtTmp = (&((LPBYTE)fodInfos->ofnInfos.lpstrFilter)[iStrIndex]);
1135 if(!lpstrExtTmp)
1136 break;
1138 lpstrExt = (LPSTR) MemAlloc(strlen(lpstrExtTmp));
1139 if(!lpstrExt)
1140 break;
1142 strcpy(lpstrExt,lpstrExtTmp);
1144 iStrIndex += strlen(lpstrExt) +1;
1146 /* Add the item at the end of the combo */
1147 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB,lpstrTmp);
1148 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos++,lpstrExt);
1150 /* Set the current filter to the one specified
1151 in the initialisation structure */
1152 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB,
1153 fodInfos->ofnInfos.nFilterIndex);
1155 lpstrFilter = (LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
1156 fodInfos->ofnInfos.nFilterIndex);
1157 if(lpstrFilter)
1159 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc((strlen(lpstrFilter)+1)*2);
1160 lstrcpyAtoW(fodInfos->ShellInfos.lpstrCurrentFilter,strlwr(lpstrFilter));
1163 return NOERROR;
1166 /***********************************************************************
1167 * FILEDLG95_FILETYPE_OnCommand
1169 * WM_COMMAND of the file type combo box
1170 * If the function succeeds, the return value is nonzero.
1172 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
1174 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1176 switch(wNotifyCode)
1178 case CBN_CLOSEUP:
1180 LPSTR lpstrFilter;
1182 /* Get the current item of the filetype combo box */
1183 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
1185 /* Set the current filter with the current selection */
1186 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1187 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1189 lpstrFilter = (LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
1190 iItem);
1191 if(lpstrFilter)
1193 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc((strlen(lpstrFilter)+1)*2);
1194 lstrcpyAtoW(fodInfos->ShellInfos.lpstrCurrentFilter,(LPSTR)strlwr((LPSTR)lpstrFilter));
1197 /* Refresh the actual view to display the included items*/
1198 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1202 return FALSE;
1204 /***********************************************************************
1205 * FILEDLG95_FILETYPE_SearchExt
1207 * Search for pidl in the lookin combo box
1208 * returns the index of the found item
1210 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPSTR lpstrExt)
1212 int i = 0;
1213 int iCount = CBGetCount(hwnd);
1215 TRACE("\n");
1217 for(;i<iCount;i++)
1219 LPSTR ext = (LPSTR) CBGetItemDataPtr(hwnd,i);
1221 if(!_stricmp(lpstrExt,ext))
1222 return i;
1226 return -1;
1229 /***********************************************************************
1230 * FILEDLG95_FILETYPE_Clean
1232 * Clean the memory used by the filetype combo box
1234 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
1236 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1237 int iPos;
1238 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
1240 TRACE("\n");
1242 /* Delete each string of the combo and their associated data */
1243 for(iPos = iCount-1;iPos>=0;iPos--)
1245 MemFree((LPVOID)(CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos)));
1246 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
1248 /* Current filter */
1249 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1250 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1254 /***********************************************************************
1255 * FILEDLG95_LOOKIN_Init
1257 * Initialisation of the look in combo box
1259 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo)
1261 IShellFolder *psfRoot, *psfDrives;
1262 IEnumIDList *lpeRoot, *lpeDrives;
1263 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
1265 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
1267 TRACE("\n");
1269 liInfos->iMaxIndentation = 0;
1271 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
1273 /* Initialise data of Desktop folder */
1274 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
1275 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
1276 SHFree(pidlTmp);
1278 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
1280 SHGetDesktopFolder(&psfRoot);
1282 if (psfRoot)
1284 /* enumerate the contents of the desktop */
1285 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
1287 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
1289 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
1291 /* special handling for CSIDL_DRIVES */
1292 if (ILIsEqual(pidlTmp, pidlDrives))
1294 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
1296 /* enumerate the drives */
1297 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
1299 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
1301 pidlAbsTmp = ILCombine(pidlTmp, pidlTmp1);
1302 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
1303 SHFree(pidlAbsTmp);
1304 SHFree(pidlTmp1);
1306 IEnumIDList_Release(lpeDrives);
1308 IShellFolder_Release(psfDrives);
1311 SHFree(pidlTmp);
1313 IEnumIDList_Release(lpeRoot);
1317 IShellFolder_Release(psfRoot);
1318 SHFree(pidlDrives);
1320 return NOERROR;
1323 /***********************************************************************
1324 * FILEDLG95_LOOKIN_DrawItem
1326 * WM_DRAWITEM message handler
1328 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
1330 COLORREF crWin = GetSysColor(COLOR_WINDOW);
1331 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
1332 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
1333 RECT rectText;
1334 RECT rectIcon;
1335 SHFILEINFOA sfi;
1336 HIMAGELIST ilItemImage;
1337 int iIndentation;
1338 LPSFOLDER tmpFolder;
1341 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
1343 TRACE("\n");
1345 if(pDIStruct->itemID == -1)
1346 return 0;
1348 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
1349 pDIStruct->itemID)))
1350 return 0;
1353 if(pDIStruct->itemID == liInfos->uSelectedItem)
1355 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
1357 &sfi,
1358 sizeof (SHFILEINFOA),
1359 SHGFI_PIDL | SHGFI_SMALLICON |
1360 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
1361 SHGFI_DISPLAYNAME );
1363 else
1365 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
1367 &sfi,
1368 sizeof (SHFILEINFOA),
1369 SHGFI_PIDL | SHGFI_SMALLICON |
1370 SHGFI_SYSICONINDEX |
1371 SHGFI_DISPLAYNAME);
1374 /* Is this item selected ?*/
1375 if(pDIStruct->itemState & ODS_SELECTED)
1377 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
1378 SetBkColor(pDIStruct->hDC,crHighLight);
1379 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,(HBRUSH)crHighLight);
1381 else
1383 SetTextColor(pDIStruct->hDC,crText);
1384 SetBkColor(pDIStruct->hDC,crWin);
1385 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,(HBRUSH)crWin);
1388 /* Do not indent item if drawing in the edit of the combo*/
1389 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
1391 iIndentation = 0;
1392 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
1394 &sfi,
1395 sizeof (SHFILEINFOA),
1396 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
1397 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
1400 else
1402 iIndentation = tmpFolder->m_iIndent;
1404 /* Draw text and icon */
1406 /* Initialise the icon display area */
1407 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
1408 rectIcon.top = pDIStruct->rcItem.top;
1409 rectIcon.right = rectIcon.left + ICONWIDTH;
1410 rectIcon.bottom = pDIStruct->rcItem.bottom;
1412 /* Initialise the text display area */
1413 rectText.left = rectIcon.right;
1414 rectText.top = pDIStruct->rcItem.top + YTEXTOFFSET;
1415 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
1416 rectText.bottom = pDIStruct->rcItem.bottom;
1419 /* Draw the icon from the image list */
1420 COMDLG32_ImageList_Draw(ilItemImage,
1421 sfi.iIcon,
1422 pDIStruct->hDC,
1423 rectIcon.left,
1424 rectIcon.top,
1425 ILD_TRANSPARENT );
1427 /* Draw the associated text */
1428 if(sfi.szDisplayName)
1429 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
1432 return NOERROR;
1435 /***********************************************************************
1436 * FILEDLG95_LOOKIN_OnCommand
1438 * LookIn combo box WM_COMMAND message handler
1439 * If the function succeeds, the return value is nonzero.
1441 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
1443 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1445 TRACE("\n");
1447 switch(wNotifyCode)
1449 case CBN_CLOSEUP:
1451 LPSFOLDER tmpFolder;
1452 int iItem;
1454 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
1456 tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
1457 iItem);
1460 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
1461 tmpFolder->pidlItem,
1462 SBSP_ABSOLUTE)))
1464 return TRUE;
1466 break;
1470 return FALSE;
1473 /***********************************************************************
1474 * FILEDLG95_LOOKIN_AddItem
1476 * Adds an absolute pidl item to the lookin combo box
1477 * returns the index of the inserted item
1479 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
1481 LPITEMIDLIST pidlNext;
1482 SHFILEINFOA sfi;
1483 SFOLDER *tmpFolder = MemAlloc(sizeof(SFOLDER));
1484 LookInInfos *liInfos;
1486 TRACE("\n");
1488 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
1489 return -1;
1491 tmpFolder->m_iIndent = 0;
1493 if(!pidl)
1494 return -1;
1496 /* Calculate the indentation of the item in the lookin*/
1497 pidlNext = pidl;
1498 while( (pidlNext=ILGetNext(pidlNext)) )
1500 tmpFolder->m_iIndent++;
1503 tmpFolder->pidlItem = ILClone(pidl);
1505 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
1506 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
1508 SHGetFileInfoA((LPSTR)pidl,
1510 &sfi,
1511 sizeof(sfi),
1512 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
1513 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES);
1516 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
1518 int iItemID;
1519 /* Add the item at the end of the list */
1520 if(iInsertId < 0)
1522 iItemID = CBAddString(hwnd,sfi.szDisplayName);
1524 /* Insert the item at the iInsertId position*/
1525 else
1527 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
1530 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
1531 return iItemID;
1534 return -1;
1538 /***********************************************************************
1539 * FILEDLG95_LOOKIN_InsertItemAfterParent
1541 * Insert an item below its parent
1543 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
1546 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
1547 int iParentPos;
1549 TRACE("\n");
1551 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
1553 if(iParentPos < 0)
1555 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
1558 /* Free pidlParent memory */
1559 SHFree((LPVOID)pidlParent);
1561 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
1564 /***********************************************************************
1565 * FILEDLG95_LOOKIN_SelectItem
1567 * Adds an absolute pidl item to the lookin combo box
1568 * returns the index of the inserted item
1570 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
1572 int iItemPos;
1573 LookInInfos *liInfos;
1575 TRACE("\n");
1577 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
1579 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
1581 if(iItemPos < 0)
1583 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
1584 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
1587 else
1589 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
1590 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
1592 int iRemovedItem;
1594 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
1595 break;
1596 if(iRemovedItem < iItemPos)
1597 iItemPos--;
1601 CBSetCurSel(hwnd,iItemPos);
1602 liInfos->uSelectedItem = iItemPos;
1604 return 0;
1608 /***********************************************************************
1609 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
1611 * Remove the item with an expansion level over iExpansionLevel
1613 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
1615 int iItemPos;
1617 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
1619 TRACE("\n");
1621 if(liInfos->iMaxIndentation <= 2)
1622 return -1;
1624 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
1626 SFOLDER *tmpFolder;
1627 tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
1628 CBDeleteString(hwnd,iItemPos);
1629 liInfos->iMaxIndentation--;
1631 return iItemPos;
1634 return -1;
1637 /***********************************************************************
1638 * FILEDLG95_LOOKIN_SearchItem
1640 * Search for pidl in the lookin combo box
1641 * returns the index of the found item
1643 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
1645 int i = 0;
1646 int iCount = CBGetCount(hwnd);
1648 TRACE("\n");
1650 for(;i<iCount;i++)
1652 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
1654 if(iSearchMethod == SEARCH_PIDL && ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
1655 return i;
1656 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
1657 return i;
1661 return -1;
1664 /***********************************************************************
1665 * FILEDLG95_LOOKIN_Clean
1667 * Clean the memory used by the lookin combo box
1669 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
1671 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1672 int iPos;
1673 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
1675 TRACE("\n");
1677 /* Delete each string of the combo and their associated data */
1678 for(iPos = iCount-1;iPos>=0;iPos--)
1680 MemFree((LPVOID)(CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos)));
1681 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
1683 /* LookInInfos structure */
1684 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
1688 * TOOLS
1691 /***********************************************************************
1692 * GetName
1694 * Get the pidl's display name (relative to folder) and
1695 * put it in lpstrFileName.
1697 * Return NOERROR on success,
1698 * E_FAIL otherwise
1701 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
1703 STRRET str;
1704 HRESULT hRes;
1706 TRACE("%p %p\n", lpsf, pidl);
1708 if(!lpsf)
1710 HRESULT hRes;
1711 SHGetDesktopFolder(&lpsf);
1712 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
1713 IShellFolder_Release(lpsf);
1714 return hRes;
1717 /* Get the display name of the pidl relative to the folder */
1718 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf,
1719 pidl,
1720 dwFlags,
1721 &str)))
1723 return StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
1725 return E_FAIL;
1728 /***********************************************************************
1729 * GetShellFolderFromPidl
1731 * pidlRel is the item pidl relative
1732 * Return the IShellFolder of the absolute pidl
1734 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
1736 IShellFolder *psf = NULL,*psfParent;
1738 TRACE("%p\n", pidlAbs);
1740 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
1742 psf = psfParent;
1743 if(pidlAbs && pidlAbs->mkid.cb)
1745 if(FAILED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
1747 psf = NULL;
1750 IShellFolder_Release(psfParent);
1753 return psf;
1757 /***********************************************************************
1758 * GetParentPidl
1760 * Return the LPITEMIDLIST to the parent of the pidl in the list
1762 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
1764 LPITEMIDLIST pidlParent;
1766 TRACE("%p\n", pidl);
1768 pidlParent = ILClone(pidl);
1769 ILRemoveLastID(pidlParent);
1771 return pidlParent;
1775 /***********************************************************************
1776 * GetPidlFromName
1778 * returns the pidl of the file name relative to folder
1779 * NULL if an error occured
1781 LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPCSTR lpcstrFileName)
1783 LPITEMIDLIST pidl;
1784 ULONG ulEaten;
1785 wchar_t lpwstrDirName[MAX_PATH];
1787 TRACE("sf=%p file=%s\n", psf, lpcstrFileName);
1789 if(!lpcstrFileName)
1790 return NULL;
1792 MultiByteToWideChar(CP_ACP,
1793 MB_PRECOMPOSED,
1794 lpcstrFileName,
1795 -1,
1796 (LPWSTR)lpwstrDirName,
1797 MAX_PATH);
1801 if(SUCCEEDED(IShellFolder_ParseDisplayName(psf,
1803 NULL,
1804 (LPWSTR)lpwstrDirName,
1805 &ulEaten,
1806 &pidl,
1807 NULL)))
1809 return pidl;
1811 return NULL;
1814 /***********************************************************************
1815 * GetFileExtension
1818 BOOL GetFileExtension(IShellFolder *psf,LPITEMIDLIST pidl,LPSTR lpstrFileExtension)
1820 char FileName[MAX_PATH];
1821 int result;
1822 char *pdest;
1823 int ch = '.';
1825 if(SUCCEEDED(GetName(psf,pidl,SHGDN_NORMAL,FileName)))
1827 if(!(pdest = strrchr( FileName, ch )))
1828 return FALSE;
1830 result = pdest - FileName + 1;
1831 strcpy(lpstrFileExtension,&FileName[result]);
1832 return TRUE;
1834 return FALSE;
1838 * Memory allocation methods */
1839 void *MemAlloc(UINT size)
1841 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
1844 void MemFree(void *mem)
1846 if(mem)
1848 HeapFree(GetProcessHeap(),0,mem);