bc7b51b2e41268d6b61a1cb429a1cb07f6a4244c
[reactos.git] / reactos / dll / win32 / comdlg32 / filedlg.c
1 /*
2 * COMMDLG - File Open Dialogs Win95 look and feel
3 *
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
6 *
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.
11 *
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.
16 *
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 *
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).
28 *
29 * FIXME: any hook gets a OPENFILENAMEA structure
30 *
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
32 *
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
34 *
35 * FIXME: algorithm for selecting the initial directory is too simple
36 *
37 * FIXME: add to recent docs
38 *
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING,
41 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
42 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
43 *
44 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
45 *
46 *
47 */
48
49 #include "config.h"
50 #include "wine/port.h"
51
52 #include <ctype.h>
53 #include <stdlib.h>
54 #include <stdarg.h>
55 #include <stdio.h>
56 #include <string.h>
57
58 #define COBJMACROS
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
61
62 #include "windef.h"
63 #include "winbase.h"
64 #include "winternl.h"
65 #include "winnls.h"
66 #include "wingdi.h"
67 #include "winreg.h"
68 #include "winuser.h"
69 #include "commdlg.h"
70 #include "dlgs.h"
71 #include "cdlg.h"
72 #include "filedlg31.h"
73 #include "cderr.h"
74 #include "shellapi.h"
75 #include "shlobj.h"
76 #include "filedlgbrowser.h"
77 #include "shlwapi.h"
78
79 #include "wine/unicode.h"
80 #include "wine/debug.h"
81
82 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
83
84 #define UNIMPLEMENTED_FLAGS \
85 (OFN_DONTADDTORECENT |\
86 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
87 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
88 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
89
90 #define IsHooked(fodInfos) \
91 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
92 /***********************************************************************
93 * Data structure and global variables
94 */
95 typedef struct SFolder
96 {
97 int m_iImageIndex; /* Index of picture in image list */
98 HIMAGELIST hImgList;
99 int m_iIndent; /* Indentation index */
100 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
101
102 } SFOLDER,*LPSFOLDER;
103
104 typedef struct tagLookInInfo
105 {
106 int iMaxIndentation;
107 UINT uSelectedItem;
108 } LookInInfos;
109
110 typedef struct tagFD32_PRIVATE
111 {
112 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
113 } FD32_PRIVATE, *PFD32_PRIVATE;
114
115
116 /***********************************************************************
117 * Defines and global variables
118 */
119
120 /* Draw item constant */
121 #define ICONWIDTH 18
122 #define XTEXTOFFSET 3
123
124 /* AddItem flags*/
125 #define LISTEND -1
126
127 /* SearchItem methods */
128 #define SEARCH_PIDL 1
129 #define SEARCH_EXP 2
130 #define ITEM_NOTFOUND -1
131
132 /* Undefined windows message sent by CreateViewObject*/
133 #define WM_GETISHELLBROWSER WM_USER+7
134
135 /* NOTE
136 * Those macros exist in windowsx.h. However, you can't really use them since
137 * they rely on the UNICODE defines and can't be used inside Wine itself.
138 */
139
140 /* Combo box macros */
141 #define CBAddString(hwnd,str) \
142 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
143
144 #define CBInsertString(hwnd,str,pos) \
145 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
146
147 #define CBDeleteString(hwnd,pos) \
148 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
149
150 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
151 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
152
153 #define CBGetItemDataPtr(hwnd,iItemId) \
154 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
155
156 #define CBGetLBText(hwnd,iItemId,str) \
157 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
158
159 #define CBGetCurSel(hwnd) \
160 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
161
162 #define CBSetCurSel(hwnd,pos) \
163 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
164
165 #define CBGetCount(hwnd) \
166 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
167 #define CBShowDropDown(hwnd,show) \
168 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
169 #define CBSetItemHeight(hwnd,index,height) \
170 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
171
172 #define CBSetExtendedUI(hwnd,flag) \
173 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
174
175 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
176 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
177
178 /***********************************************************************
179 * Prototypes
180 */
181
182 /* Internal functions used by the dialog */
183 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
184 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
185 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
186 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
187 static BOOL FILEDLG95_OnOpen(HWND hwnd);
188 static LRESULT FILEDLG95_InitControls(HWND hwnd);
189 static void FILEDLG95_Clean(HWND hwnd);
190
191 /* Functions used by the shell navigation */
192 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
193 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
194 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
195 static void FILEDLG95_SHELL_Clean(HWND hwnd);
196 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
197
198 /* Functions used by the EDIT box */
199 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
200
201 /* Functions used by the filetype combo box */
202 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
203 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
204 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
205 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
206
207 /* Functions used by the Look In combo box */
208 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
209 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
210 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
211 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
212 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
213 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
214 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
215 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
216 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
217
218 /* Miscellaneous tool functions */
219 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
220 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
221 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
222 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
223
224 /* Shell memory allocation */
225 static void *MemAlloc(UINT size);
226 static void MemFree(void *mem);
227
228 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
229 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
230 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
231 static BOOL BrowseSelectedFolder(HWND hwnd);
232
233 /***********************************************************************
234 * GetFileName95
235 *
236 * Creates an Open common dialog box that lets the user select
237 * the drive, directory, and the name of a file or set of files to open.
238 *
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.
242 */
243 static BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
244 {
245
246 LRESULT lRes;
247 LPCVOID template;
248 HRSRC hRes;
249 HANDLE hDlgTmpl = 0;
250 HRESULT hr;
251
252 /* test for missing functionality */
253 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
254 {
255 FIXME("Flags 0x%08x not yet implemented\n",
256 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
257 }
258
259 /* Create the dialog from a template */
260
261 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
262 {
263 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
264 return FALSE;
265 }
266 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
267 !(template = LockResource( hDlgTmpl )))
268 {
269 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
270 return FALSE;
271 }
272
273 /* old style hook messages */
274 if (IsHooked(fodInfos))
275 {
276 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
277 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
278 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
279 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
280 }
281
282 /* Some shell namespace extensions depend on COM being initialized. */
283 hr = OleInitialize(NULL);
284
285 if (fodInfos->unicode)
286 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
287 template,
288 fodInfos->ofnInfos->hwndOwner,
289 FileOpenDlgProc95,
290 (LPARAM) fodInfos);
291 else
292 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
293 (LPCDLGTEMPLATEA) template,
294 fodInfos->ofnInfos->hwndOwner,
295 FileOpenDlgProc95,
296 (LPARAM) fodInfos);
297 if (SUCCEEDED(hr))
298 OleUninitialize();
299
300 /* Unable to create the dialog */
301 if( lRes == -1)
302 return FALSE;
303
304 return lRes;
305 }
306
307 /***********************************************************************
308 * GetFileDialog95A
309 *
310 * Call GetFileName95 with this structure and clean the memory.
311 *
312 * IN : The OPENFILENAMEA initialisation structure passed to
313 * GetOpenFileNameA win api function (see filedlg.c)
314 */
315 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
316 {
317 BOOL ret;
318 FileOpenDlgInfos fodInfos;
319 LPSTR lpstrSavDir = NULL;
320 LPWSTR title = NULL;
321 LPWSTR defext = NULL;
322 LPWSTR filter = NULL;
323 LPWSTR customfilter = NULL;
324
325 /* Initialize CommDlgExtendedError() */
326 COMDLG32_SetCommDlgExtendedError(0);
327
328 /* Initialize FileOpenDlgInfos structure */
329 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
330
331 /* Pass in the original ofn */
332 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
333
334 /* save current directory */
335 if (ofn->Flags & OFN_NOCHANGEDIR)
336 {
337 lpstrSavDir = MemAlloc(MAX_PATH);
338 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
339 }
340
341 fodInfos.unicode = FALSE;
342
343 /* convert all the input strings to unicode */
344 if(ofn->lpstrInitialDir)
345 {
346 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
347 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
348 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
349 }
350 else
351 fodInfos.initdir = NULL;
352
353 if(ofn->lpstrFile)
354 {
355 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
356 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
357 }
358 else
359 fodInfos.filename = NULL;
360
361 if(ofn->lpstrDefExt)
362 {
363 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
364 defext = MemAlloc((len+1)*sizeof(WCHAR));
365 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
366 }
367 fodInfos.defext = defext;
368
369 if(ofn->lpstrTitle)
370 {
371 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
372 title = MemAlloc((len+1)*sizeof(WCHAR));
373 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
374 }
375 fodInfos.title = title;
376
377 if (ofn->lpstrFilter)
378 {
379 LPCSTR s;
380 int n, len;
381
382 /* filter is a list... title\0ext\0......\0\0 */
383 s = ofn->lpstrFilter;
384 while (*s) s = s+strlen(s)+1;
385 s++;
386 n = s - ofn->lpstrFilter;
387 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
388 filter = MemAlloc(len*sizeof(WCHAR));
389 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
390 }
391 fodInfos.filter = filter;
392
393 /* convert lpstrCustomFilter */
394 if (ofn->lpstrCustomFilter)
395 {
396 LPCSTR s;
397 int n, len;
398
399 /* customfilter contains a pair of strings... title\0ext\0 */
400 s = ofn->lpstrCustomFilter;
401 if (*s) s = s+strlen(s)+1;
402 if (*s) s = s+strlen(s)+1;
403 n = s - ofn->lpstrCustomFilter;
404 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
405 customfilter = MemAlloc(len*sizeof(WCHAR));
406 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
407 }
408 fodInfos.customfilter = customfilter;
409
410 /* Initialize the dialog property */
411 fodInfos.DlgInfos.dwDlgProp = 0;
412 fodInfos.DlgInfos.hwndCustomDlg = NULL;
413
414 switch(iDlgType)
415 {
416 case OPEN_DIALOG :
417 ret = GetFileName95(&fodInfos);
418 break;
419 case SAVE_DIALOG :
420 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
421 ret = GetFileName95(&fodInfos);
422 break;
423 default :
424 ret = 0;
425 }
426
427 if (lpstrSavDir)
428 {
429 SetCurrentDirectoryA(lpstrSavDir);
430 MemFree(lpstrSavDir);
431 }
432
433 MemFree(title);
434 MemFree(defext);
435 MemFree(filter);
436 MemFree(customfilter);
437 MemFree(fodInfos.initdir);
438 MemFree(fodInfos.filename);
439
440 TRACE("selected file: %s\n",ofn->lpstrFile);
441
442 return ret;
443 }
444
445 /***********************************************************************
446 * GetFileDialog95W
447 *
448 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
449 * Call GetFileName95 with this structure and clean the memory.
450 *
451 */
452 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
453 {
454 BOOL ret;
455 FileOpenDlgInfos fodInfos;
456 LPWSTR lpstrSavDir = NULL;
457
458 /* Initialize CommDlgExtendedError() */
459 COMDLG32_SetCommDlgExtendedError(0);
460
461 /* Initialize FileOpenDlgInfos structure */
462 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
463
464 /* Pass in the original ofn */
465 fodInfos.ofnInfos = ofn;
466
467 fodInfos.title = ofn->lpstrTitle;
468 fodInfos.defext = ofn->lpstrDefExt;
469 fodInfos.filter = ofn->lpstrFilter;
470 fodInfos.customfilter = ofn->lpstrCustomFilter;
471
472 /* convert string arguments, save others */
473 if(ofn->lpstrFile)
474 {
475 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
476 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
477 }
478 else
479 fodInfos.filename = NULL;
480
481 if(ofn->lpstrInitialDir)
482 {
483 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
484 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
485 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
486 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
487 }
488 else
489 fodInfos.initdir = NULL;
490
491 /* save current directory */
492 if (ofn->Flags & OFN_NOCHANGEDIR)
493 {
494 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
495 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
496 }
497
498 fodInfos.unicode = TRUE;
499
500 switch(iDlgType)
501 {
502 case OPEN_DIALOG :
503 ret = GetFileName95(&fodInfos);
504 break;
505 case SAVE_DIALOG :
506 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
507 ret = GetFileName95(&fodInfos);
508 break;
509 default :
510 ret = 0;
511 }
512
513 if (lpstrSavDir)
514 {
515 SetCurrentDirectoryW(lpstrSavDir);
516 MemFree(lpstrSavDir);
517 }
518
519 /* restore saved IN arguments and convert OUT arguments back */
520 MemFree(fodInfos.filename);
521 MemFree(fodInfos.initdir);
522 return ret;
523 }
524
525 /******************************************************************************
526 * COMDLG32_GetDisplayNameOf [internal]
527 *
528 * Helper function to get the display name for a pidl.
529 */
530 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
531 LPSHELLFOLDER psfDesktop;
532 STRRET strret;
533
534 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
535 return FALSE;
536
537 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
538 IShellFolder_Release(psfDesktop);
539 return FALSE;
540 }
541
542 IShellFolder_Release(psfDesktop);
543 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
544 }
545
546 /***********************************************************************
547 * ArrangeCtrlPositions [internal]
548 *
549 * NOTE: Do not change anything here without a lot of testing.
550 */
551 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
552 {
553 HWND hwndChild, hwndStc32;
554 RECT rectParent, rectChild, rectStc32;
555 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
556
557 /* Take into account if open as read only checkbox and help button
558 * are hidden
559 */
560 if (hide_help)
561 {
562 RECT rectHelp, rectCancel;
563 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
564 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
565 /* subtract the height of the help button plus the space between
566 * the help button and the cancel button to the height of the dialog
567 */
568 help_fixup = rectHelp.bottom - rectCancel.bottom;
569 }
570
571 /*
572 There are two possibilities to add components to the default file dialog box.
573
574 By default, all the new components are added below the standard dialog box (the else case).
575
576 However, if there is a static text component with the stc32 id, a special case happens.
577 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
578 in the window and the cx and cy indicate how to size the window.
579 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
580 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
581
582 */
583
584 GetClientRect(hwndParentDlg, &rectParent);
585
586 /* when arranging controls we have to use fixed parent size */
587 rectParent.bottom -= help_fixup;
588
589 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
590 if (hwndStc32)
591 {
592 GetWindowRect(hwndStc32, &rectStc32);
593 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
594
595 /* set the size of the stc32 control according to the size of
596 * client area of the parent dialog
597 */
598 SetWindowPos(hwndStc32, 0,
599 0, 0,
600 rectParent.right, rectParent.bottom,
601 SWP_NOMOVE | SWP_NOZORDER);
602 }
603 else
604 SetRectEmpty(&rectStc32);
605
606 /* this part moves controls of the child dialog */
607 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
608 while (hwndChild)
609 {
610 if (hwndChild != hwndStc32)
611 {
612 GetWindowRect(hwndChild, &rectChild);
613 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
614
615 /* move only if stc32 exist */
616 if (hwndStc32 && rectChild.left > rectStc32.right)
617 {
618 LONG old_left = rectChild.left;
619
620 /* move to the right of visible controls of the parent dialog */
621 rectChild.left += rectParent.right;
622 rectChild.left -= rectStc32.right;
623
624 child_width_fixup = rectChild.left - old_left;
625 }
626 /* move even if stc32 doesn't exist */
627 if (rectChild.top >= rectStc32.bottom)
628 {
629 LONG old_top = rectChild.top;
630
631 /* move below visible controls of the parent dialog */
632 rectChild.top += rectParent.bottom;
633 rectChild.top -= rectStc32.bottom - rectStc32.top;
634
635 child_height_fixup = rectChild.top - old_top;
636 }
637
638 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
639 0, 0, SWP_NOSIZE | SWP_NOZORDER);
640 }
641 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
642 }
643
644 /* this part moves controls of the parent dialog */
645 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
646 while (hwndChild)
647 {
648 if (hwndChild != hwndChildDlg)
649 {
650 GetWindowRect(hwndChild, &rectChild);
651 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
652
653 /* left,top of stc32 marks the position of controls
654 * from the parent dialog
655 */
656 rectChild.left += rectStc32.left;
657 rectChild.top += rectStc32.top;
658
659 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
660 0, 0, SWP_NOSIZE | SWP_NOZORDER);
661 }
662 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
663 }
664
665 /* calculate the size of the resulting dialog */
666
667 /* here we have to use original parent size */
668 GetClientRect(hwndParentDlg, &rectParent);
669 GetClientRect(hwndChildDlg, &rectChild);
670
671 if (hwndStc32)
672 {
673 rectChild.right += child_width_fixup;
674 rectChild.bottom += child_height_fixup;
675
676 if (rectParent.right > rectChild.right)
677 {
678 rectParent.right += rectChild.right;
679 rectParent.right -= rectStc32.right - rectStc32.left;
680 }
681 else
682 {
683 rectParent.right = rectChild.right;
684 }
685
686 if (rectParent.bottom > rectChild.bottom)
687 {
688 rectParent.bottom += rectChild.bottom;
689 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
690 }
691 else
692 {
693 /* child dialog is higher, unconditionally set new dialog
694 * height to its size (help_fixup will be subtracted below)
695 */
696 rectParent.bottom = rectChild.bottom + help_fixup;
697 }
698 }
699 else
700 {
701 rectParent.bottom += rectChild.bottom;
702 }
703
704 /* finally use fixed parent size */
705 rectParent.bottom -= help_fixup;
706
707 /* set the size of the parent dialog */
708 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
709 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
710 SetWindowPos(hwndParentDlg, 0,
711 0, 0,
712 rectParent.right - rectParent.left,
713 rectParent.bottom - rectParent.top,
714 SWP_NOMOVE | SWP_NOZORDER);
715 }
716
717 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
718 {
719 switch(uMsg) {
720 case WM_INITDIALOG:
721 return TRUE;
722 }
723 return FALSE;
724 }
725
726 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
727 {
728 LPCVOID template;
729 HRSRC hRes;
730 HANDLE hDlgTmpl = 0;
731 HWND hChildDlg = 0;
732
733 TRACE("\n");
734
735 /*
736 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
737 * structure's hInstance parameter is not a HINSTANCE, but
738 * instead a pointer to a template resource to use.
739 */
740 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
741 {
742 HINSTANCE hinst;
743 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
744 {
745 hinst = COMDLG32_hInstance;
746 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
747 {
748 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
749 return NULL;
750 }
751 }
752 else
753 {
754 hinst = fodInfos->ofnInfos->hInstance;
755 if(fodInfos->unicode)
756 {
757 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
758 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
759 }
760 else
761 {
762 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
763 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
764 }
765 if (!hRes)
766 {
767 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
768 return NULL;
769 }
770 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
771 !(template = LockResource( hDlgTmpl )))
772 {
773 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
774 return NULL;
775 }
776 }
777 if (fodInfos->unicode)
778 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
779 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
780 (LPARAM)fodInfos->ofnInfos);
781 else
782 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
783 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
784 (LPARAM)fodInfos->ofnInfos);
785 if(hChildDlg)
786 {
787 ShowWindow(hChildDlg,SW_SHOW);
788 return hChildDlg;
789 }
790 }
791 else if( IsHooked(fodInfos))
792 {
793 RECT rectHwnd;
794 struct {
795 DLGTEMPLATE tmplate;
796 WORD menu,class,title;
797 } temp;
798 GetClientRect(hwnd,&rectHwnd);
799 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
800 temp.tmplate.dwExtendedStyle = 0;
801 temp.tmplate.cdit = 0;
802 temp.tmplate.x = 0;
803 temp.tmplate.y = 0;
804 temp.tmplate.cx = 0;
805 temp.tmplate.cy = 0;
806 temp.menu = temp.class = temp.title = 0;
807
808 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
809 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
810
811 return hChildDlg;
812 }
813 return NULL;
814 }
815
816 /***********************************************************************
817 * SendCustomDlgNotificationMessage
818 *
819 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
820 */
821
822 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
823 {
824 LRESULT hook_result = 0;
825
826 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
827
828 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
829
830 if(!fodInfos) return 0;
831
832 if(fodInfos->DlgInfos.hwndCustomDlg)
833 {
834 TRACE("CALL NOTIFY for %x\n", uCode);
835 if(fodInfos->unicode)
836 {
837 OFNOTIFYW ofnNotify;
838 ofnNotify.hdr.hwndFrom=hwndParentDlg;
839 ofnNotify.hdr.idFrom=0;
840 ofnNotify.hdr.code = uCode;
841 ofnNotify.lpOFN = fodInfos->ofnInfos;
842 ofnNotify.pszFile = NULL;
843 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
844 }
845 else
846 {
847 OFNOTIFYA ofnNotify;
848 ofnNotify.hdr.hwndFrom=hwndParentDlg;
849 ofnNotify.hdr.idFrom=0;
850 ofnNotify.hdr.code = uCode;
851 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
852 ofnNotify.pszFile = NULL;
853 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
854 }
855 TRACE("RET NOTIFY\n");
856 }
857 TRACE("Retval: 0x%08lx\n", hook_result);
858 return hook_result;
859 }
860
861 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
862 {
863 UINT len, total;
864 WCHAR *p, *buffer;
865 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
866
867 TRACE("CDM_GETFILEPATH:\n");
868
869 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
870 return -1;
871
872 /* get path and filenames */
873 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
874 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
875 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
876 if (len)
877 {
878 p = buffer + strlenW(buffer);
879 *p++ = '\\';
880 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
881 }
882 if (fodInfos->unicode)
883 {
884 total = strlenW( buffer) + 1;
885 if (result) lstrcpynW( result, buffer, size );
886 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
887 }
888 else
889 {
890 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
891 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
892 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
893 }
894 HeapFree( GetProcessHeap(), 0, buffer );
895 return total;
896 }
897
898 /***********************************************************************
899 * FILEDLG95_HandleCustomDialogMessages
900 *
901 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
902 */
903 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
904 {
905 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
906 WCHAR lpstrPath[MAX_PATH];
907 INT_PTR retval;
908
909 if(!fodInfos) return FALSE;
910
911 switch(uMsg)
912 {
913 case CDM_GETFILEPATH:
914 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
915 break;
916
917 case CDM_GETFOLDERPATH:
918 TRACE("CDM_GETFOLDERPATH:\n");
919 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
920 if (lParam)
921 {
922 if (fodInfos->unicode)
923 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
924 else
925 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
926 (LPSTR)lParam, (int)wParam, NULL, NULL);
927 }
928 retval = lstrlenW(lpstrPath);
929 break;
930
931 case CDM_GETFOLDERIDLIST:
932 retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
933 if (retval <= wParam)
934 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
935 break;
936
937 case CDM_GETSPEC:
938 TRACE("CDM_GETSPEC:\n");
939 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
940 if (lParam)
941 {
942 if (fodInfos->unicode)
943 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
944 else
945 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
946 }
947 break;
948
949 case CDM_SETCONTROLTEXT:
950 TRACE("CDM_SETCONTROLTEXT:\n");
951 if ( lParam )
952 {
953 if( fodInfos->unicode )
954 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
955 else
956 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
957 }
958 retval = TRUE;
959 break;
960
961 case CDM_HIDECONTROL:
962 /* MSDN states that it should fail for not OFN_EXPLORER case */
963 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
964 {
965 HWND control = GetDlgItem( hwnd, wParam );
966 if (control) ShowWindow( control, SW_HIDE );
967 retval = TRUE;
968 }
969 else retval = FALSE;
970 break;
971
972 default:
973 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
974 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
975 return FALSE;
976 }
977 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
978 return TRUE;
979 }
980
981 /***********************************************************************
982 * FileOpenDlgProc95
983 *
984 * File open dialog procedure
985 */
986 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
987 {
988 #if 0
989 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
990 #endif
991
992 switch(uMsg)
993 {
994 case WM_INITDIALOG:
995 {
996 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
997
998 /* Adds the FileOpenDlgInfos in the property list of the dialog
999 so it will be easily accessible through a GetPropA(...) */
1000 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
1001
1002 FILEDLG95_InitControls(hwnd);
1003
1004 fodInfos->DlgInfos.hwndCustomDlg =
1005 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1006
1007 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1008 FILEDLG95_FillControls(hwnd, wParam, lParam);
1009
1010 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1011 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1012 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1013 return 0;
1014 }
1015 case WM_COMMAND:
1016 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1017 case WM_DRAWITEM:
1018 {
1019 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1020 {
1021 case IDC_LOOKIN:
1022 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1023 return TRUE;
1024 }
1025 }
1026 return FALSE;
1027
1028 case WM_GETISHELLBROWSER:
1029 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1030
1031 case WM_DESTROY:
1032 RemovePropA(hwnd, FileOpenDlgInfosStr);
1033 return FALSE;
1034
1035 case WM_NOTIFY:
1036 {
1037 LPNMHDR lpnmh = (LPNMHDR)lParam;
1038 UINT stringId = -1;
1039
1040 /* set up the button tooltips strings */
1041 if(TTN_GETDISPINFOA == lpnmh->code )
1042 {
1043 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1044 switch(lpnmh->idFrom )
1045 {
1046 /* Up folder button */
1047 case FCIDM_TB_UPFOLDER:
1048 stringId = IDS_UPFOLDER;
1049 break;
1050 /* New folder button */
1051 case FCIDM_TB_NEWFOLDER:
1052 stringId = IDS_NEWFOLDER;
1053 break;
1054 /* List option button */
1055 case FCIDM_TB_SMALLICON:
1056 stringId = IDS_LISTVIEW;
1057 break;
1058 /* Details option button */
1059 case FCIDM_TB_REPORTVIEW:
1060 stringId = IDS_REPORTVIEW;
1061 break;
1062 /* Desktop button */
1063 case FCIDM_TB_DESKTOP:
1064 stringId = IDS_TODESKTOP;
1065 break;
1066 default:
1067 stringId = 0;
1068 }
1069 lpdi->hinst = COMDLG32_hInstance;
1070 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1071 }
1072 return FALSE;
1073 }
1074 default :
1075 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1076 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1077 return FALSE;
1078 }
1079 }
1080
1081 /***********************************************************************
1082 * FILEDLG95_InitControls
1083 *
1084 * WM_INITDIALOG message handler (before hook notification)
1085 */
1086 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1087 {
1088 int win2000plus = 0;
1089 int win98plus = 0;
1090 int handledPath = FALSE;
1091 OSVERSIONINFOW osVi;
1092 static const WCHAR szwSlash[] = { '\\', 0 };
1093 static const WCHAR szwStar[] = { '*',0 };
1094
1095 static const TBBUTTON tbb[] =
1096 {
1097 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1098 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1099 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1100 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1101 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1102 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1103 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1104 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1105 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1106 };
1107 TBADDBITMAP tba[2];
1108 RECT rectTB;
1109 RECT rectlook;
1110 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1111
1112 tba[0].hInst = HINST_COMMCTRL;
1113 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1114 tba[1].hInst = COMDLG32_hInstance;
1115 tba[1].nID = 800;
1116
1117 TRACE("%p\n", fodInfos);
1118
1119 /* Get windows version emulating */
1120 osVi.dwOSVersionInfoSize = sizeof(osVi);
1121 GetVersionExW(&osVi);
1122 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1123 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1124 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1125 win2000plus = (osVi.dwMajorVersion > 4);
1126 if (win2000plus) win98plus = TRUE;
1127 }
1128 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1129
1130 /* Get the hwnd of the controls */
1131 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1132 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1133 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1134
1135 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1136 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1137
1138 /* construct the toolbar */
1139 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1140 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1141
1142 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1143 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1144 rectTB.left = rectlook.right;
1145 rectTB.top = rectlook.top-1;
1146
1147 if (fodInfos->unicode)
1148 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1149 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1150 rectTB.left, rectTB.top,
1151 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1152 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1153 else
1154 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1155 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1156 rectTB.left, rectTB.top,
1157 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1158 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1159
1160 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1161
1162 /* FIXME: use TB_LOADIMAGES when implemented */
1163 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1164 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba[0]);
1165 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 1, (LPARAM) &tba[1]);
1166
1167 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) &tbb);
1168 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1169
1170 /* Set the window text with the text specified in the OPENFILENAME structure */
1171 if(fodInfos->title)
1172 {
1173 SetWindowTextW(hwnd,fodInfos->title);
1174 }
1175 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1176 {
1177 WCHAR buf[16];
1178 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1179 SetWindowTextW(hwnd, buf);
1180 }
1181
1182 /* Initialise the file name edit control */
1183 handledPath = FALSE;
1184 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1185
1186 if(fodInfos->filename)
1187 {
1188 /* 1. If win2000 or higher and filename contains a path, use it
1189 in preference over the lpstrInitialDir */
1190 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1191 WCHAR tmpBuf[MAX_PATH];
1192 WCHAR *nameBit;
1193 DWORD result;
1194
1195 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1196 if (result) {
1197
1198 /* nameBit is always shorter than the original filename */
1199 lstrcpyW(fodInfos->filename,nameBit);
1200
1201 *nameBit = 0x00;
1202 if (fodInfos->initdir == NULL)
1203 MemFree(fodInfos->initdir);
1204 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1205 lstrcpyW(fodInfos->initdir, tmpBuf);
1206 handledPath = TRUE;
1207 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1208 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1209 }
1210 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1211
1212 } else {
1213 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1214 }
1215 }
1216
1217 /* 2. (All platforms) If initdir is not null, then use it */
1218 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1219 (*fodInfos->initdir!=0x00))
1220 {
1221 /* Work out the proper path as supplied one might be relative */
1222 /* (Here because supplying '.' as dir browses to My Computer) */
1223 if (handledPath==FALSE) {
1224 WCHAR tmpBuf[MAX_PATH];
1225 WCHAR tmpBuf2[MAX_PATH];
1226 WCHAR *nameBit;
1227 DWORD result;
1228
1229 lstrcpyW(tmpBuf, fodInfos->initdir);
1230 if( PathFileExistsW(tmpBuf) ) {
1231 /* initdir does not have to be a directory. If a file is
1232 * specified, the dir part is taken */
1233 if( PathIsDirectoryW(tmpBuf)) {
1234 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1235 lstrcatW(tmpBuf, szwSlash);
1236 }
1237 lstrcatW(tmpBuf, szwStar);
1238 }
1239 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1240 if (result) {
1241 *nameBit = 0x00;
1242 MemFree(fodInfos->initdir);
1243 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1244 lstrcpyW(fodInfos->initdir, tmpBuf2);
1245 handledPath = TRUE;
1246 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1247 }
1248 }
1249 else if (fodInfos->initdir)
1250 {
1251 MemFree(fodInfos->initdir);
1252 fodInfos->initdir = NULL;
1253 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1254 }
1255 }
1256 }
1257
1258 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1259 (*fodInfos->initdir==0x00)))
1260 {
1261 /* 3. All except w2k+: if filename contains a path use it */
1262 if (!win2000plus && fodInfos->filename &&
1263 *fodInfos->filename &&
1264 strpbrkW(fodInfos->filename, szwSlash)) {
1265 WCHAR tmpBuf[MAX_PATH];
1266 WCHAR *nameBit;
1267 DWORD result;
1268
1269 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1270 tmpBuf, &nameBit);
1271 if (result) {
1272 int len;
1273
1274 /* nameBit is always shorter than the original filename */
1275 lstrcpyW(fodInfos->filename, nameBit);
1276 *nameBit = 0x00;
1277
1278 len = lstrlenW(tmpBuf);
1279 MemFree(fodInfos->initdir);
1280 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1281 lstrcpyW(fodInfos->initdir, tmpBuf);
1282
1283 handledPath = TRUE;
1284 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1285 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1286 }
1287 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1288 }
1289
1290 /* 4. win98+ and win2000+ if any files of specified filter types in
1291 current directory, use it */
1292 if ( win98plus && handledPath == FALSE &&
1293 fodInfos->filter && *fodInfos->filter) {
1294
1295 BOOL searchMore = TRUE;
1296 LPCWSTR lpstrPos = fodInfos->filter;
1297 WIN32_FIND_DATAW FindFileData;
1298 HANDLE hFind;
1299
1300 while (searchMore)
1301 {
1302 /* filter is a list... title\0ext\0......\0\0 */
1303
1304 /* Skip the title */
1305 if(! *lpstrPos) break; /* end */
1306 lpstrPos += lstrlenW(lpstrPos) + 1;
1307
1308 /* See if any files exist in the current dir with this extension */
1309 if(! *lpstrPos) break; /* end */
1310
1311 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1312
1313 if (hFind == INVALID_HANDLE_VALUE) {
1314 /* None found - continue search */
1315 lpstrPos += lstrlenW(lpstrPos) + 1;
1316
1317 } else {
1318 searchMore = FALSE;
1319
1320 MemFree(fodInfos->initdir);
1321 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1322 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1323
1324 handledPath = TRUE;
1325 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1326 debugstr_w(lpstrPos));
1327 break;
1328 }
1329 }
1330 }
1331
1332 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1333
1334 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1335 if (handledPath == FALSE && (win2000plus || win98plus)) {
1336 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1337
1338 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1339 {
1340 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1341 {
1342 /* last fallback */
1343 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1344 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1345 } else {
1346 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1347 }
1348 } else {
1349 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1350 }
1351 handledPath = TRUE;
1352 } else if (handledPath==FALSE) {
1353 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1354 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1355 handledPath = TRUE;
1356 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1357 }
1358 }
1359 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1360 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1361
1362 /* Must the open as read only check box be checked ?*/
1363 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1364 {
1365 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1366 }
1367
1368 /* Must the open as read only check box be hidden? */
1369 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1370 {
1371 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1372 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1373 }
1374
1375 /* Must the help button be hidden? */
1376 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1377 {
1378 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1379 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1380 }
1381
1382 /* change Open to Save */
1383 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1384 {
1385 WCHAR buf[16];
1386 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1387 SetDlgItemTextW(hwnd, IDOK, buf);
1388 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1389 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1390 }
1391 return 0;
1392 }
1393
1394 /***********************************************************************
1395 * FILEDLG95_ResizeControls
1396 *
1397 * WM_INITDIALOG message handler (after hook notification)
1398 */
1399 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1400 {
1401 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1402
1403 if (fodInfos->DlgInfos.hwndCustomDlg)
1404 {
1405 RECT rc;
1406 UINT flags = SWP_NOACTIVATE;
1407
1408 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1409 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1410
1411 /* resize the custom dialog to the parent size */
1412 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1413 GetClientRect(hwnd, &rc);
1414 else
1415 {
1416 /* our own fake template is zero sized and doesn't have children, so
1417 * there is no need to resize it. Picasa depends on it.
1418 */
1419 flags |= SWP_NOSIZE;
1420 SetRectEmpty(&rc);
1421 }
1422 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1423 0, 0, rc.right, rc.bottom, flags);
1424 }
1425 else
1426 {
1427 /* Resize the height, if open as read only checkbox ad help button are
1428 * hidden and we are not using a custom template nor a customDialog
1429 */
1430 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1431 (!(fodInfos->ofnInfos->Flags &
1432 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1433 {
1434 RECT rectDlg, rectHelp, rectCancel;
1435 GetWindowRect(hwnd, &rectDlg);
1436 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1437 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1438 /* subtract the height of the help button plus the space between the help
1439 * button and the cancel button to the height of the dialog
1440 */
1441 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1442 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1443 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1444 }
1445 }
1446 return TRUE;
1447 }
1448
1449 /***********************************************************************
1450 * FILEDLG95_FillControls
1451 *
1452 * WM_INITDIALOG message handler (after hook notification)
1453 */
1454 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1455 {
1456 LPITEMIDLIST pidlItemId = NULL;
1457
1458 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1459
1460 TRACE("dir=%s file=%s\n",
1461 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1462
1463 /* Get the initial directory pidl */
1464
1465 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1466 {
1467 WCHAR path[MAX_PATH];
1468
1469 GetCurrentDirectoryW(MAX_PATH,path);
1470 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1471 }
1472
1473 /* Initialise shell objects */
1474 FILEDLG95_SHELL_Init(hwnd);
1475
1476 /* Initialize the Look In combo box */
1477 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1478
1479 /* Initialize the filter combo box */
1480 FILEDLG95_FILETYPE_Init(hwnd);
1481
1482 /* Browse to the initial directory */
1483 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1484
1485 /* Free pidlItem memory */
1486 COMDLG32_SHFree(pidlItemId);
1487
1488 return TRUE;
1489 }
1490 /***********************************************************************
1491 * FILEDLG95_Clean
1492 *
1493 * Regroups all the cleaning functions of the filedlg
1494 */
1495 void FILEDLG95_Clean(HWND hwnd)
1496 {
1497 FILEDLG95_FILETYPE_Clean(hwnd);
1498 FILEDLG95_LOOKIN_Clean(hwnd);
1499 FILEDLG95_SHELL_Clean(hwnd);
1500 }
1501 /***********************************************************************
1502 * FILEDLG95_OnWMCommand
1503 *
1504 * WM_COMMAND message handler
1505 */
1506 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1507 {
1508 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1509 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1510 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1511
1512 switch(wID)
1513 {
1514 /* OK button */
1515 case IDOK:
1516 FILEDLG95_OnOpen(hwnd);
1517 break;
1518 /* Cancel button */
1519 case IDCANCEL:
1520 FILEDLG95_Clean(hwnd);
1521 EndDialog(hwnd, FALSE);
1522 break;
1523 /* Filetype combo box */
1524 case IDC_FILETYPE:
1525 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1526 break;
1527 /* LookIn combo box */
1528 case IDC_LOOKIN:
1529 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1530 break;
1531
1532 /* --- toolbar --- */
1533 /* Up folder button */
1534 case FCIDM_TB_UPFOLDER:
1535 FILEDLG95_SHELL_UpFolder(hwnd);
1536 break;
1537 /* New folder button */
1538 case FCIDM_TB_NEWFOLDER:
1539 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1540 break;
1541 /* List option button */
1542 case FCIDM_TB_SMALLICON:
1543 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1544 break;
1545 /* Details option button */
1546 case FCIDM_TB_REPORTVIEW:
1547 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1548 break;
1549 /* Details option button */
1550 case FCIDM_TB_DESKTOP:
1551 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1552 break;
1553
1554 case IDC_FILENAME:
1555 break;
1556
1557 }
1558 /* Do not use the listview selection anymore */
1559 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1560 return 0;
1561 }
1562
1563 /***********************************************************************
1564 * FILEDLG95_OnWMGetIShellBrowser
1565 *
1566 * WM_GETISHELLBROWSER message handler
1567 */
1568 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1569 {
1570
1571 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1572
1573 TRACE("\n");
1574
1575 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1576
1577 return TRUE;
1578 }
1579
1580
1581 /***********************************************************************
1582 * FILEDLG95_SendFileOK
1583 *
1584 * Sends the CDN_FILEOK notification if required
1585 *
1586 * RETURNS
1587 * TRUE if the dialog should close
1588 * FALSE if the dialog should not be closed
1589 */
1590 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1591 {
1592 /* ask the hook if we can close */
1593 if(IsHooked(fodInfos))
1594 {
1595 LRESULT retval;
1596
1597 TRACE("---\n");
1598 /* First send CDN_FILEOK as MSDN doc says */
1599 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1600 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1601 {
1602 TRACE("canceled\n");
1603 return (retval == 0);
1604 }
1605
1606 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1607 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1608 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1609 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1610 {
1611 TRACE("canceled\n");
1612 return (retval == 0);
1613 }
1614 }
1615 return TRUE;
1616 }
1617
1618 /***********************************************************************
1619 * FILEDLG95_OnOpenMultipleFiles
1620 *
1621 * Handles the opening of multiple files.
1622 *
1623 * FIXME
1624 * check destination buffer size
1625 */
1626 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1627 {
1628 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1629 UINT nCount, nSizePath;
1630 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1631
1632 TRACE("\n");
1633
1634 if(fodInfos->unicode)
1635 {
1636 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1637 ofn->lpstrFile[0] = '\0';
1638 }
1639 else
1640 {
1641 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1642 ofn->lpstrFile[0] = '\0';
1643 }
1644
1645 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1646
1647 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1648 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1649 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1650 {
1651 LPWSTR lpstrTemp = lpstrFileList;
1652
1653 for ( nCount = 0; nCount < nFileCount; nCount++ )
1654 {
1655 LPITEMIDLIST pidl;
1656
1657 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1658 if (!pidl)
1659 {
1660 WCHAR lpstrNotFound[100];
1661 WCHAR lpstrMsg[100];
1662 WCHAR tmp[400];
1663 static const WCHAR nl[] = {'\n',0};
1664
1665 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1666 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1667
1668 lstrcpyW(tmp, lpstrTemp);
1669 lstrcatW(tmp, nl);
1670 lstrcatW(tmp, lpstrNotFound);
1671 lstrcatW(tmp, nl);
1672 lstrcatW(tmp, lpstrMsg);
1673
1674 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1675 return FALSE;
1676 }
1677
1678 /* move to the next file in the list of files */
1679 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1680 COMDLG32_SHFree(pidl);
1681 }
1682 }
1683
1684 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1685 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1686 {
1687 /* For "oldstyle" dialog the components have to
1688 be separated by blanks (not '\0'!) and short
1689 filenames have to be used! */
1690 FIXME("Components have to be separated by blanks\n");
1691 }
1692 if(fodInfos->unicode)
1693 {
1694 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1695 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1696 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1697 }
1698 else
1699 {
1700 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1701
1702 if (ofn->lpstrFile != NULL)
1703 {
1704 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1705 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1706 if (ofn->nMaxFile > nSizePath)
1707 {
1708 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1709 ofn->lpstrFile + nSizePath,
1710 ofn->nMaxFile - nSizePath, NULL, NULL);
1711 }
1712 }
1713 }
1714
1715 fodInfos->ofnInfos->nFileOffset = nSizePath;
1716 fodInfos->ofnInfos->nFileExtension = 0;
1717
1718 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1719 return FALSE;
1720
1721 /* clean and exit */
1722 FILEDLG95_Clean(hwnd);
1723 return EndDialog(hwnd,TRUE);
1724 }
1725
1726 /***********************************************************************
1727 * FILEDLG95_OnOpen
1728 *
1729 * Ok button WM_COMMAND message handler
1730 *
1731 * If the function succeeds, the return value is nonzero.
1732 */
1733 #define ONOPEN_BROWSE 1
1734 #define ONOPEN_OPEN 2
1735 #define ONOPEN_SEARCH 3
1736 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1737 {
1738 WCHAR strMsgTitle[MAX_PATH];
1739 WCHAR strMsgText [MAX_PATH];
1740 if (idCaption)
1741 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1742 else
1743 strMsgTitle[0] = '\0';
1744 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1745 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1746 }
1747
1748 BOOL FILEDLG95_OnOpen(HWND hwnd)
1749 {
1750 LPWSTR lpstrFileList;
1751 UINT nFileCount = 0;
1752 UINT sizeUsed = 0;
1753 BOOL ret = TRUE;
1754 WCHAR lpstrPathAndFile[MAX_PATH];
1755 WCHAR lpstrTemp[MAX_PATH];
1756 LPSHELLFOLDER lpsf = NULL;
1757 int nOpenAction;
1758 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1759
1760 TRACE("hwnd=%p\n", hwnd);
1761
1762 /* get the files from the edit control */
1763 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1764
1765 /* try if the user selected a folder in the shellview */
1766 if(nFileCount == 0)
1767 {
1768 BrowseSelectedFolder(hwnd);
1769 return FALSE;
1770 }
1771
1772 if(nFileCount > 1)
1773 {
1774 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1775 goto ret;
1776 }
1777
1778 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1779
1780 /*
1781 Step 1: Build a complete path name from the current folder and
1782 the filename or path in the edit box.
1783 Special cases:
1784 - the path in the edit box is a root path
1785 (with or without drive letter)
1786 - the edit box contains ".." (or a path with ".." in it)
1787 */
1788
1789 /* Get the current directory name */
1790 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1791 {
1792 /* last fallback */
1793 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1794 }
1795 PathAddBackslashW(lpstrPathAndFile);
1796
1797 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1798
1799 /* if the user specified a fully qualified path use it */
1800 if(PathIsRelativeW(lpstrFileList))
1801 {
1802 lstrcatW(lpstrPathAndFile, lpstrFileList);
1803 }
1804 else
1805 {
1806 /* does the path have a drive letter? */
1807 if (PathGetDriveNumberW(lpstrFileList) == -1)
1808 lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
1809 else
1810 lstrcpyW(lpstrPathAndFile, lpstrFileList);
1811 }
1812
1813 /* resolve "." and ".." */
1814 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1815 lstrcpyW(lpstrPathAndFile, lpstrTemp);
1816 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1817
1818 MemFree(lpstrFileList);
1819
1820 /*
1821 Step 2: here we have a cleaned up path
1822
1823 We have to parse the path step by step to see if we have to browse
1824 to a folder if the path points to a directory or the last
1825 valid element is a directory.
1826
1827 valid variables:
1828 lpstrPathAndFile: cleaned up path
1829 */
1830
1831 if (nFileCount &&
1832 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1833 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1834 nOpenAction = ONOPEN_OPEN;
1835 else
1836 nOpenAction = ONOPEN_BROWSE;
1837
1838 /* don't apply any checks with OFN_NOVALIDATE */
1839 {
1840 LPWSTR lpszTemp, lpszTemp1;
1841 LPITEMIDLIST pidl = NULL;
1842 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1843
1844 /* check for invalid chars */
1845 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1846 {
1847 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1848 ret = FALSE;
1849 goto ret;
1850 }
1851
1852 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1853
1854 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1855 while (lpszTemp1)
1856 {
1857 LPSHELLFOLDER lpsfChild;
1858 WCHAR lpwstrTemp[MAX_PATH];
1859 DWORD dwEaten, dwAttributes;
1860 LPWSTR p;
1861
1862 lstrcpyW(lpwstrTemp, lpszTemp);
1863 p = PathFindNextComponentW(lpwstrTemp);
1864
1865 if (!p) break; /* end of path */
1866
1867 *p = 0;
1868 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
1869
1870 /* There are no wildcards when OFN_NOVALIDATE is set */
1871 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1872 {
1873 static const WCHAR wszWild[] = { '*', '?', 0 };
1874 /* if the last element is a wildcard do a search */
1875 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1876 {
1877 nOpenAction = ONOPEN_SEARCH;
1878 break;
1879 }
1880 }
1881 lpszTemp1 = lpszTemp;
1882
1883 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1884
1885 /* append a backslash to drive letters */
1886 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1887 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1888 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1889 {
1890 PathAddBackslashW(lpwstrTemp);
1891 }
1892
1893 dwAttributes = SFGAO_FOLDER;
1894 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1895 {
1896 /* the path component is valid, we have a pidl of the next path component */
1897 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
1898 if(dwAttributes & SFGAO_FOLDER)
1899 {
1900 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1901 {
1902 ERR("bind to failed\n"); /* should not fail */
1903 break;
1904 }
1905 IShellFolder_Release(lpsf);
1906 lpsf = lpsfChild;
1907 lpsfChild = NULL;
1908 }
1909 else
1910 {
1911 TRACE("value\n");
1912
1913 /* end dialog, return value */
1914 nOpenAction = ONOPEN_OPEN;
1915 break;
1916 }
1917 COMDLG32_SHFree(pidl);
1918 pidl = NULL;
1919 }
1920 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1921 {
1922 if(*lpszTemp || /* points to trailing null for last path element */
1923 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
1924 {
1925 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1926 {
1927 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1928 break;
1929 }
1930 }
1931 else
1932 {
1933 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1934 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1935 {
1936 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1937 break;
1938 }
1939 }
1940 /* change to the current folder */
1941 nOpenAction = ONOPEN_OPEN;
1942 break;
1943 }
1944 else
1945 {
1946 nOpenAction = ONOPEN_OPEN;
1947 break;
1948 }
1949 }
1950 if(pidl) COMDLG32_SHFree(pidl);
1951 }
1952
1953 /*
1954 Step 3: here we have a cleaned up and validated path
1955
1956 valid variables:
1957 lpsf: ShellFolder bound to the rightmost valid path component
1958 lpstrPathAndFile: cleaned up path
1959 nOpenAction: action to do
1960 */
1961 TRACE("end validate sf=%p\n", lpsf);
1962
1963 switch(nOpenAction)
1964 {
1965 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1966 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1967 {
1968 int iPos;
1969 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1970 DWORD len;
1971
1972 /* replace the current filter */
1973 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1974 len = lstrlenW(lpszTemp)+1;
1975 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1976 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1977
1978 /* set the filter cb to the extension when possible */
1979 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1980 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1981 }
1982 /* fall through */
1983 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1984 TRACE("ONOPEN_BROWSE\n");
1985 {
1986 IPersistFolder2 * ppf2;
1987 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1988 {
1989 LPITEMIDLIST pidlCurrent;
1990 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1991 IPersistFolder2_Release(ppf2);
1992 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1993 {
1994 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE)))
1995 {
1996 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
1997 }
1998 }
1999 else if( nOpenAction == ONOPEN_SEARCH )
2000 {
2001 if (fodInfos->Shell.FOIShellView)
2002 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2003 }
2004 COMDLG32_SHFree(pidlCurrent);
2005 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2006 }
2007 }
2008 ret = FALSE;
2009 break;
2010 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2011 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2012 {
2013 WCHAR *ext = NULL;
2014
2015 /* update READONLY check box flag */
2016 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2017 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2018 else
2019 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2020
2021 /* Attach the file extension with file name*/
2022 ext = PathFindExtensionW(lpstrPathAndFile);
2023 if (! *ext)
2024 {
2025 /* if no extension is specified with file name, then */
2026 /* attach the extension from file filter or default one */
2027
2028 WCHAR *filterExt = NULL;
2029 LPWSTR lpstrFilter = NULL;
2030 static const WCHAR szwDot[] = {'.',0};
2031 int PathLength = lstrlenW(lpstrPathAndFile);
2032
2033 /* Attach the dot*/
2034 lstrcatW(lpstrPathAndFile, szwDot);
2035
2036 /*Get the file extension from file type filter*/
2037 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2038 fodInfos->ofnInfos->nFilterIndex-1);
2039
2040 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2041 filterExt = PathFindExtensionW(lpstrFilter);
2042
2043 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2044 lstrcatW(lpstrPathAndFile, filterExt + 1);
2045 else if ( fodInfos->defext ) /* attach the default file extension*/
2046 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2047
2048 /* In Open dialog: if file does not exist try without extension */
2049 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2050 lpstrPathAndFile[PathLength] = '\0';
2051 }
2052
2053 if (fodInfos->defext) /* add default extension */
2054 {
2055 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2056 if (*ext)
2057 ext++;
2058 if (!lstrcmpiW(fodInfos->defext, ext))
2059 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2060 else
2061 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2062 }
2063
2064 /* In Save dialog: check if the file already exists */
2065 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2066 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2067 && PathFileExistsW(lpstrPathAndFile))
2068 {
2069 WCHAR lpstrOverwrite[100];
2070 int answer;
2071
2072 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2073 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2074 MB_YESNO | MB_ICONEXCLAMATION);
2075 if (answer == IDNO)
2076 {
2077 ret = FALSE;
2078 goto ret;
2079 }
2080 }
2081
2082 /* In Open dialog: check if it should be created if it doesn't exist */
2083 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2084 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2085 && !PathFileExistsW(lpstrPathAndFile))
2086 {
2087 WCHAR lpstrCreate[100];
2088 int answer;
2089
2090 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2091 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2092 MB_YESNO | MB_ICONEXCLAMATION);
2093 if (answer == IDNO)
2094 {
2095 ret = FALSE;
2096 goto ret;
2097 }
2098 }
2099
2100 /* Check that the size of the file does not exceed buffer size.
2101 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2102 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2103 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2104 {
2105
2106 /* fill destination buffer */
2107 if (fodInfos->ofnInfos->lpstrFile)
2108 {
2109 if(fodInfos->unicode)
2110 {
2111 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2112
2113 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2114 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2115 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2116 }
2117 else
2118 {
2119 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2120
2121 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2122 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2123 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2124 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2125 }
2126 }
2127
2128 if(fodInfos->unicode)
2129 {
2130 LPWSTR lpszTemp;
2131
2132 /* set filename offset */
2133 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2134 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2135
2136 /* set extension offset */
2137 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2138 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2139 }
2140 else
2141 {
2142 LPSTR lpszTemp;
2143 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2144
2145 /* set filename offset */
2146 lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2147 fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2148
2149 /* set extension offset */
2150 lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2151 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2152 }
2153
2154 /* set the lpstrFileTitle */
2155 if(fodInfos->ofnInfos->lpstrFileTitle)
2156 {
2157 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2158 if(fodInfos->unicode)
2159 {
2160 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2161 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2162 }
2163 else
2164 {
2165 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2166 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2167 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2168 }
2169 }
2170
2171 /* copy currently selected filter to lpstrCustomFilter */
2172 if (fodInfos->ofnInfos->lpstrCustomFilter)
2173 {
2174 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2175 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2176 NULL, 0, NULL, NULL);
2177 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2178 {
2179 LPSTR s = ofn->lpstrCustomFilter;
2180 s += strlen(ofn->lpstrCustomFilter)+1;
2181 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2182 s, len, NULL, NULL);
2183 }
2184 }
2185
2186
2187 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2188 goto ret;
2189
2190 TRACE("close\n");
2191 FILEDLG95_Clean(hwnd);
2192 ret = EndDialog(hwnd, TRUE);
2193 }
2194 else
2195 {
2196 WORD size;
2197
2198 size = lstrlenW(lpstrPathAndFile) + 1;
2199 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2200 size += 1;
2201 /* return needed size in first two bytes of lpstrFile */
2202 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2203 FILEDLG95_Clean(hwnd);
2204 ret = EndDialog(hwnd, FALSE);
2205 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2206 }
2207 goto ret;
2208 }
2209 break;
2210 }
2211
2212 ret:
2213 if(lpsf) IShellFolder_Release(lpsf);
2214 return ret;
2215 }
2216
2217 /***********************************************************************
2218 * FILEDLG95_SHELL_Init
2219 *
2220 * Initialisation of the shell objects
2221 */
2222 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2223 {
2224 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2225
2226 TRACE("\n");
2227
2228 /*
2229 * Initialisation of the FileOpenDialogInfos structure
2230 */
2231
2232 /* Shell */
2233
2234 /*ShellInfos */
2235 fodInfos->ShellInfos.hwndOwner = hwnd;
2236
2237 /* Disable multi-select if flag not set */
2238 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2239 {
2240 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2241 }
2242 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2243 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2244
2245 /* Construct the IShellBrowser interface */
2246 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2247
2248 return NOERROR;
2249 }
2250
2251 /***********************************************************************
2252 * FILEDLG95_SHELL_ExecuteCommand
2253 *
2254 * Change the folder option and refresh the view
2255 * If the function succeeds, the return value is nonzero.
2256 */
2257 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2258 {
2259 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2260
2261 IContextMenu * pcm;
2262 TRACE("(%p,%p)\n", hwnd, lpVerb);
2263
2264 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2265 SVGIO_BACKGROUND,
2266 &IID_IContextMenu,
2267 (LPVOID*)&pcm)))
2268 {
2269 CMINVOKECOMMANDINFO ci;
2270 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2271 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2272 ci.lpVerb = lpVerb;
2273 ci.hwnd = hwnd;
2274
2275 IContextMenu_InvokeCommand(pcm, &ci);
2276 IContextMenu_Release(pcm);
2277 }
2278
2279 return FALSE;
2280 }
2281
2282 /***********************************************************************
2283 * FILEDLG95_SHELL_UpFolder
2284 *
2285 * Browse to the specified object
2286 * If the function succeeds, the return value is nonzero.
2287 */
2288 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2289 {
2290 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2291
2292 TRACE("\n");
2293
2294 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2295 NULL,
2296 SBSP_PARENT)))
2297 {
2298 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2299 return TRUE;
2300 }
2301 return FALSE;
2302 }
2303
2304 /***********************************************************************
2305 * FILEDLG95_SHELL_BrowseToDesktop
2306 *
2307 * Browse to the Desktop
2308 * If the function succeeds, the return value is nonzero.
2309 */
2310 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2311 {
2312 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2313 LPITEMIDLIST pidl;
2314 HRESULT hres;
2315
2316 TRACE("\n");
2317
2318 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2319 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2320 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2321 COMDLG32_SHFree(pidl);
2322 return SUCCEEDED(hres);
2323 }
2324 /***********************************************************************
2325 * FILEDLG95_SHELL_Clean
2326 *
2327 * Cleans the memory used by shell objects
2328 */
2329 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2330 {
2331 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2332
2333 TRACE("\n");
2334
2335 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2336
2337 /* clean Shell interfaces */
2338 if (fodInfos->Shell.FOIShellView)
2339 {
2340 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2341 IShellView_Release(fodInfos->Shell.FOIShellView);
2342 }
2343 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2344 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2345 if (fodInfos->Shell.FOIDataObject)
2346 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2347 }
2348
2349 /***********************************************************************
2350 * FILEDLG95_FILETYPE_Init
2351 *
2352 * Initialisation of the file type combo box
2353 */
2354 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2355 {
2356 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2357 int nFilters = 0; /* number of filters */
2358 int nFilterIndexCB;
2359
2360 TRACE("\n");
2361
2362 if(fodInfos->customfilter)
2363 {
2364 /* customfilter has one entry... title\0ext\0
2365 * Set first entry of combo box item with customfilter
2366 */
2367 LPWSTR lpstrExt;
2368 LPCWSTR lpstrPos = fodInfos->customfilter;
2369
2370 /* Get the title */
2371 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2372
2373 /* Copy the extensions */
2374 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2375 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2376 lstrcpyW(lpstrExt,lpstrPos);
2377
2378 /* Add the item at the end of the combo */
2379 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2380 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2381 nFilters++;
2382 }
2383 if(fodInfos->filter)
2384 {
2385 LPCWSTR lpstrPos = fodInfos->filter;
2386
2387 for(;;)
2388 {
2389 /* filter is a list... title\0ext\0......\0\0
2390 * Set the combo item text to the title and the item data
2391 * to the ext
2392 */
2393 LPCWSTR lpstrDisplay;
2394 LPWSTR lpstrExt;
2395
2396 /* Get the title */
2397 if(! *lpstrPos) break; /* end */
2398 lpstrDisplay = lpstrPos;
2399 lpstrPos += lstrlenW(lpstrPos) + 1;
2400
2401 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2402
2403 nFilters++;
2404
2405 /* Copy the extensions */
2406 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2407 lstrcpyW(lpstrExt,lpstrPos);
2408 lpstrPos += lstrlenW(lpstrPos) + 1;
2409
2410 /* Add the item at the end of the combo */
2411 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2412
2413 /* malformed filters are added anyway... */
2414 if (!*lpstrExt) break;
2415 }
2416 }
2417
2418 /*
2419 * Set the current filter to the one specified
2420 * in the initialisation structure
2421 */
2422 if (fodInfos->filter || fodInfos->customfilter)
2423 {
2424 LPWSTR lpstrFilter;
2425
2426 /* Check to make sure our index isn't out of bounds. */
2427 if ( fodInfos->ofnInfos->nFilterIndex >
2428 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2429 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2430
2431 /* set default filter index */
2432 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2433 fodInfos->ofnInfos->nFilterIndex = 1;
2434
2435 /* calculate index of Combo Box item */
2436 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2437 if (fodInfos->customfilter == NULL)
2438 nFilterIndexCB--;
2439
2440 /* Set the current index selection. */
2441 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2442
2443 /* Get the corresponding text string from the combo box. */
2444 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2445 nFilterIndexCB);
2446
2447 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2448 lpstrFilter = NULL;
2449
2450 if(lpstrFilter)
2451 {
2452 DWORD len;
2453 CharLowerW(lpstrFilter); /* lowercase */
2454 len = lstrlenW(lpstrFilter)+1;
2455 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2456 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2457 }
2458 } else
2459 fodInfos->ofnInfos->nFilterIndex = 0;
2460 return S_OK;
2461 }
2462
2463 /***********************************************************************
2464 * FILEDLG95_FILETYPE_OnCommand
2465 *
2466 * WM_COMMAND of the file type combo box
2467 * If the function succeeds, the return value is nonzero.
2468 */
2469 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2470 {
2471 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2472
2473 switch(wNotifyCode)
2474 {
2475 case CBN_SELENDOK:
2476 {
2477 LPWSTR lpstrFilter;
2478
2479 /* Get the current item of the filetype combo box */
2480 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2481
2482 /* set the current filter index */
2483 fodInfos->ofnInfos->nFilterIndex = iItem +
2484 (fodInfos->customfilter == NULL ? 1 : 0);
2485
2486 /* Set the current filter with the current selection */
2487 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2488
2489 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2490 iItem);
2491 if((INT_PTR)lpstrFilter != CB_ERR)
2492 {
2493 DWORD len;
2494 CharLowerW(lpstrFilter); /* lowercase */
2495 len = lstrlenW(lpstrFilter)+1;
2496 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2497 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2498 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2499 }
2500
2501 /* Refresh the actual view to display the included items*/
2502 if (fodInfos->Shell.FOIShellView)
2503 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2504 }
2505 }
2506 return FALSE;
2507 }
2508 /***********************************************************************
2509 * FILEDLG95_FILETYPE_SearchExt
2510 *
2511 * searches for an extension in the filetype box
2512 */
2513 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2514 {
2515 int i, iCount = CBGetCount(hwnd);
2516
2517 TRACE("%s\n", debugstr_w(lpstrExt));
2518
2519 if(iCount != CB_ERR)
2520 {
2521 for(i=0;i<iCount;i++)
2522 {
2523 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2524 return i;
2525 }
2526 }
2527 return -1;
2528 }
2529
2530 /***********************************************************************
2531 * FILEDLG95_FILETYPE_Clean
2532 *
2533 * Clean the memory used by the filetype combo box
2534 */
2535 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2536 {
2537 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2538 int iPos;
2539 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2540
2541 TRACE("\n");
2542
2543 /* Delete each string of the combo and their associated data */
2544 if(iCount != CB_ERR)
2545 {
2546 for(iPos = iCount-1;iPos>=0;iPos--)
2547 {
2548 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2549 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2550 }
2551 }
2552 /* Current filter */
2553 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2554
2555 }
2556
2557 /***********************************************************************
2558 * FILEDLG95_LOOKIN_Init
2559 *
2560 * Initialisation of the look in combo box
2561 */
2562
2563 /* Small helper function, to determine if the unixfs shell extension is rooted
2564 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2565 */
2566 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2567 HKEY hKey;
2568 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2569 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2570 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2571 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2572 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2573 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2574 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2575
2576 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2577 return FALSE;
2578
2579 RegCloseKey(hKey);
2580 return TRUE;
2581 }
2582
2583 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2584 {
2585 IShellFolder *psfRoot, *psfDrives;
2586 IEnumIDList *lpeRoot, *lpeDrives;
2587 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2588
2589 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2590
2591 TRACE("\n");
2592
2593 liInfos->iMaxIndentation = 0;
2594
2595 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2596
2597 /* set item height for both text field and listbox */
2598 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2599 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2600
2601 /* Turn on the extended UI for the combo box like Windows does */
2602 CBSetExtendedUI(hwndCombo, TRUE);
2603
2604 /* Initialise data of Desktop folder */
2605 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2606 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2607 COMDLG32_SHFree(pidlTmp);
2608
2609 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2610
2611 SHGetDesktopFolder(&psfRoot);
2612
2613 if (psfRoot)
2614 {
2615 /* enumerate the contents of the desktop */
2616 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2617 {
2618 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2619 {
2620 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2621
2622 /* If the unixfs extension is rooted, we don't expand the drives by default */
2623 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2624 {
2625 /* special handling for CSIDL_DRIVES */
2626 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2627 {
2628 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2629 {
2630 /* enumerate the drives */
2631 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2632 {
2633 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2634 {
2635 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2636 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2637 COMDLG32_SHFree(pidlAbsTmp);
2638 COMDLG32_SHFree(pidlTmp1);
2639 }
2640 IEnumIDList_Release(lpeDrives);
2641 }
2642 IShellFolder_Release(psfDrives);
2643 }
2644 }
2645 }
2646
2647 COMDLG32_SHFree(pidlTmp);
2648 }
2649 IEnumIDList_Release(lpeRoot);
2650 }
2651 IShellFolder_Release(psfRoot);
2652 }
2653
2654 COMDLG32_SHFree(pidlDrives);
2655 }
2656
2657 /***********************************************************************
2658 * FILEDLG95_LOOKIN_DrawItem
2659 *
2660 * WM_DRAWITEM message handler
2661 */
2662 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2663 {
2664 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2665 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2666 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2667 RECT rectText;
2668 RECT rectIcon;
2669 SHFILEINFOW sfi;
2670 HIMAGELIST ilItemImage;
2671 int iIndentation;
2672 TEXTMETRICW tm;
2673 LPSFOLDER tmpFolder;
2674
2675
2676 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2677
2678 TRACE("\n");
2679
2680 if(pDIStruct->itemID == -1)
2681 return 0;
2682
2683 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2684 pDIStruct->itemID)))
2685 return 0;
2686
2687
2688 if(pDIStruct->itemID == liInfos->uSelectedItem)
2689 {
2690 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2691 0,
2692 &sfi,
2693 sizeof (sfi),
2694 SHGFI_PIDL | SHGFI_SMALLICON |
2695 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2696 SHGFI_DISPLAYNAME );
2697 }
2698 else
2699 {
2700 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2701 0,
2702 &sfi,
2703 sizeof (sfi),
2704 SHGFI_PIDL | SHGFI_SMALLICON |
2705 SHGFI_SYSICONINDEX |
2706 SHGFI_DISPLAYNAME);
2707 }
2708
2709 /* Is this item selected ? */
2710 if(pDIStruct->itemState & ODS_SELECTED)
2711 {
2712 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2713 SetBkColor(pDIStruct->hDC,crHighLight);
2714 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2715 }
2716 else
2717 {
2718 SetTextColor(pDIStruct->hDC,crText);
2719 SetBkColor(pDIStruct->hDC,crWin);
2720 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2721 }
2722
2723 /* Do not indent item if drawing in the edit of the combo */
2724 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2725 {
2726 iIndentation = 0;
2727 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2728 0,
2729 &sfi,
2730 sizeof (sfi),
2731 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2732 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2733
2734 }
2735 else
2736 {
2737 iIndentation = tmpFolder->m_iIndent;
2738 }
2739 /* Draw text and icon */
2740
2741 /* Initialise the icon display area */
2742 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2743 rectIcon.top = pDIStruct->rcItem.top;
2744 rectIcon.right = rectIcon.left + ICONWIDTH;
2745 rectIcon.bottom = pDIStruct->rcItem.bottom;
2746
2747 /* Initialise the text display area */
2748 GetTextMetricsW(pDIStruct->hDC, &tm);
2749 rectText.left = rectIcon.right;
2750 rectText.top =
2751 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2752 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2753 rectText.bottom =
2754 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2755
2756 /* Draw the icon from the image list */
2757 ImageList_Draw(ilItemImage,
2758 sfi.iIcon,
2759 pDIStruct->hDC,
2760 rectIcon.left,
2761 rectIcon.top,
2762 ILD_TRANSPARENT );
2763
2764 /* Draw the associated text */
2765 if(sfi.szDisplayName)
2766 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
2767
2768
2769 return NOERROR;
2770 }
2771
2772 /***********************************************************************
2773 * FILEDLG95_LOOKIN_OnCommand
2774 *
2775 * LookIn combo box WM_COMMAND message handler
2776 * If the function succeeds, the return value is nonzero.
2777 */
2778 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2779 {
2780 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2781
2782 TRACE("%p\n", fodInfos);
2783
2784 switch(wNotifyCode)
2785 {
2786 case CBN_SELENDOK:
2787 {
2788 LPSFOLDER tmpFolder;
2789 int iItem;
2790
2791 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2792
2793 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2794 iItem)))
2795 return FALSE;
2796
2797
2798 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2799 tmpFolder->pidlItem,
2800 SBSP_ABSOLUTE)))
2801 {
2802 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2803 return TRUE;
2804 }
2805 break;
2806 }
2807
2808 }
2809 return FALSE;
2810 }
2811
2812 /***********************************************************************
2813 * FILEDLG95_LOOKIN_AddItem
2814 *
2815 * Adds an absolute pidl item to the lookin combo box
2816 * returns the index of the inserted item
2817 */
2818 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2819 {
2820 LPITEMIDLIST pidlNext;
2821 SHFILEINFOW sfi;
2822 SFOLDER *tmpFolder;
2823 LookInInfos *liInfos;
2824
2825 TRACE("%08x\n", iInsertId);
2826
2827 if(!pidl)
2828 return -1;
2829
2830 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2831 return -1;
2832
2833 tmpFolder = MemAlloc(sizeof(SFOLDER));
2834 tmpFolder->m_iIndent = 0;
2835
2836 /* Calculate the indentation of the item in the lookin*/
2837 pidlNext = pidl;
2838 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2839 {
2840 tmpFolder->m_iIndent++;
2841 }
2842
2843 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2844
2845 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2846 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2847
2848 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2849 SHGetFileInfoW((LPCWSTR)pidl,
2850 0,
2851 &sfi,
2852 sizeof(sfi),
2853 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2854 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2855
2856 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
2857
2858 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2859 {
2860 int iItemID;
2861
2862 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
2863
2864 /* Add the item at the end of the list */
2865 if(iInsertId < 0)
2866 {
2867 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2868 }
2869 /* Insert the item at the iInsertId position*/
2870 else
2871 {
2872 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2873 }
2874
2875 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2876 return iItemID;
2877 }
2878
2879 COMDLG32_SHFree( tmpFolder->pidlItem );
2880 MemFree( tmpFolder );
2881 return -1;
2882
2883 }
2884
2885 /***********************************************************************
2886 * FILEDLG95_LOOKIN_InsertItemAfterParent
2887 *
2888 * Insert an item below its parent
2889 */
2890 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2891 {
2892
2893 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2894 int iParentPos;
2895
2896 TRACE("\n");
2897
2898 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2899
2900 if(iParentPos < 0)
2901 {
2902 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2903 }
2904
2905 /* Free pidlParent memory */
2906 COMDLG32_SHFree((LPVOID)pidlParent);
2907
2908 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2909 }
2910
2911 /***********************************************************************
2912 * FILEDLG95_LOOKIN_SelectItem
2913 *
2914 * Adds an absolute pidl item to the lookin combo box
2915 * returns the index of the inserted item
2916 */
2917 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2918 {
2919 int iItemPos;
2920 LookInInfos *liInfos;
2921
2922 TRACE("\n");
2923
2924 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2925
2926 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2927
2928 if(iItemPos < 0)
2929 {
2930 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2931 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2932 }
2933
2934 else
2935 {
2936 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2937 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2938 {
2939 int iRemovedItem;
2940
2941 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2942 break;
2943 if(iRemovedItem < iItemPos)
2944 iItemPos--;
2945 }
2946 }
2947
2948 CBSetCurSel(hwnd,iItemPos);
2949 liInfos->uSelectedItem = iItemPos;
2950
2951 return 0;
2952
2953 }
2954
2955 /***********************************************************************
2956 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2957 *
2958 * Remove the item with an expansion level over iExpansionLevel
2959 */
2960 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2961 {
2962 int iItemPos;
2963
2964 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2965
2966 TRACE("\n");
2967
2968 if(liInfos->iMaxIndentation <= 2)
2969 return -1;
2970
2971 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2972 {
2973 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2974 COMDLG32_SHFree(tmpFolder->pidlItem);
2975 MemFree(tmpFolder);
2976 CBDeleteString(hwnd,iItemPos);
2977 liInfos->iMaxIndentation--;
2978
2979 return iItemPos;
2980 }
2981
2982 return -1;
2983 }
2984
2985 /***********************************************************************
2986 * FILEDLG95_LOOKIN_SearchItem
2987 *
2988 * Search for pidl in the lookin combo box
2989 * returns the index of the found item
2990 */
2991 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2992 {
2993 int i = 0;
2994 int iCount = CBGetCount(hwnd);
2995
2996 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
2997
2998 if (iCount != CB_ERR)
2999 {
3000 for(;i<iCount;i++)
3001 {
3002 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3003
3004 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3005 return i;
3006 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3007 return i;
3008 }
3009 }
3010
3011 return -1;
3012 }
3013
3014 /***********************************************************************
3015 * FILEDLG95_LOOKIN_Clean
3016 *
3017 * Clean the memory used by the lookin combo box
3018 */
3019 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3020 {
3021 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3022 int iPos;
3023 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3024
3025 TRACE("\n");
3026
3027 /* Delete each string of the combo and their associated data */
3028 if (iCount != CB_ERR)
3029 {
3030 for(iPos = iCount-1;iPos>=0;iPos--)
3031 {
3032 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3033 COMDLG32_SHFree(tmpFolder->pidlItem);
3034 MemFree(tmpFolder);
3035 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3036 }
3037 }
3038
3039 /* LookInInfos structure */
3040 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3041
3042 }
3043 /***********************************************************************
3044 * FILEDLG95_FILENAME_FillFromSelection
3045 *
3046 * fills the edit box from the cached DataObject
3047 */
3048 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3049 {
3050 FileOpenDlgInfos *fodInfos;
3051 LPITEMIDLIST pidl;
3052 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3053 WCHAR lpstrTemp[MAX_PATH];
3054 LPWSTR lpstrAllFile, lpstrCurrFile;
3055
3056 TRACE("\n");
3057 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3058
3059 /* Count how many files we have */
3060 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3061
3062 /* calculate the string length, count files */
3063 if (nFileSelected >= 1)
3064 {
3065 nLength += 3; /* first and last quotes, trailing \0 */
3066 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3067 {
3068 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3069
3070 if (pidl)
3071 {
3072 /* get the total length of the selected file names */
3073 lpstrTemp[0] = '\0';
3074 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3075
3076 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3077 {
3078 nLength += lstrlenW( lpstrTemp ) + 3;
3079 nFiles++;
3080 }
3081 COMDLG32_SHFree( pidl );
3082 }
3083 }
3084 }
3085
3086 /* allocate the buffer */
3087 if (nFiles <= 1) nLength = MAX_PATH;
3088 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3089
3090 /* Generate the string for the edit control */
3091 if(nFiles >= 1)
3092 {
3093 lpstrCurrFile = lpstrAllFile;
3094 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3095 {
3096 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3097
3098 if (pidl)
3099 {
3100 /* get the file name */
3101 lpstrTemp[0] = '\0';
3102 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3103
3104 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3105 {
3106 if ( nFiles > 1)
3107 {
3108 *lpstrCurrFile++ = '\"';
3109 lstrcpyW( lpstrCurrFile, lpstrTemp );
3110 lpstrCurrFile += lstrlenW( lpstrTemp );
3111 *lpstrCurrFile++ = '\"';
3112 *lpstrCurrFile++ = ' ';
3113 *lpstrCurrFile = 0;
3114 }
3115 else
3116 {
3117 lstrcpyW( lpstrAllFile, lpstrTemp );
3118 }
3119 }
3120 COMDLG32_SHFree( (LPVOID) pidl );
3121 }
3122 }
3123 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3124
3125 /* Select the file name like Windows does */
3126 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3127 }
3128 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3129 }
3130
3131
3132 /* copied from shell32 to avoid linking to it
3133 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3134 * is dependent on whether emulated OS is unicode or not.
3135 */
3136 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3137 {
3138 switch (src->uType)
3139 {
3140 case STRRET_WSTR:
3141 lstrcpynW(dest, src->u.pOleStr, len);
3142 COMDLG32_SHFree(src->u.pOleStr);
3143 break;
3144
3145 case STRRET_CSTR:
3146 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3147 dest[len-1] = 0;
3148 break;
3149
3150 case STRRET_OFFSET:
3151 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3152 dest[len-1] = 0;
3153 break;
3154
3155 default:
3156 FIXME("unknown type %x!\n", src->uType);
3157 if (len) *dest = '\0';
3158 return E_FAIL;
3159 }
3160 return S_OK;
3161 }
3162
3163 /***********************************************************************
3164 * FILEDLG95_FILENAME_GetFileNames
3165 *
3166 * Copies the filenames to a delimited string list.
3167 * The delimiter is specified by the parameter 'separator',
3168 * usually either a space or a nul
3169 */
3170 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3171 {
3172 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3173 UINT nStrCharCount = 0; /* index in src buffer */
3174 UINT nFileIndex = 0; /* index in dest buffer */
3175 UINT nFileCount = 0; /* number of files */
3176 UINT nStrLen = 0; /* length of string in edit control */
3177 LPWSTR lpstrEdit; /* buffer for string from edit control */
3178
3179 TRACE("\n");
3180
3181 /* get the filenames from the edit control */
3182 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3183 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3184 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3185
3186 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3187
3188 /* we might get single filename without any '"',
3189 * so we need nStrLen + terminating \0 + end-of-list \0 */
3190 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3191 *sizeUsed = 0;
3192
3193 /* build delimited file list from filenames */
3194 while ( nStrCharCount <= nStrLen )
3195 {
3196 if ( lpstrEdit[nStrCharCount]=='"' )
3197 {
3198 nStrCharCount++;
3199 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3200 {
3201 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3202 nStrCharCount++;
3203 }
3204 (*lpstrFileList)[nFileIndex++] = 0;
3205 nFileCount++;
3206 }
3207 nStrCharCount++;
3208 }
3209
3210 /* single, unquoted string */
3211 if ((nStrLen > 0) && (nFileIndex == 0) )
3212 {
3213 lstrcpyW(*lpstrFileList, lpstrEdit);
3214 nFileIndex = lstrlenW(lpstrEdit) + 1;
3215 nFileCount = 1;
3216 }
3217
3218 /* trailing \0 */
3219 (*lpstrFileList)[nFileIndex++] = '\0';
3220
3221 *sizeUsed = nFileIndex;
3222 MemFree(lpstrEdit);
3223 return nFileCount;
3224 }
3225
3226 #define SETDefFormatEtc(fe,cf,med) \
3227 { \
3228 (fe).cfFormat = cf;\
3229 (fe).dwAspect = DVASPECT_CONTENT; \
3230 (fe).ptd =NULL;\
3231 (fe).tymed = med;\
3232 (fe).lindex = -1;\
3233 };
3234
3235 /*
3236 * DATAOBJECT Helper functions
3237 */
3238
3239 /***********************************************************************
3240 * COMCTL32_ReleaseStgMedium
3241 *
3242 * like ReleaseStgMedium from ole32
3243 */
3244 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3245 {
3246 if(medium.pUnkForRelease)
3247 {
3248 IUnknown_Release(medium.pUnkForRelease);
3249 }
3250 else
3251 {
3252 GlobalUnlock(medium.u.hGlobal);
3253 GlobalFree(medium.u.hGlobal);
3254 }
3255 }
3256
3257 /***********************************************************************
3258 * GetPidlFromDataObject
3259 *
3260 * Return pidl(s) by number from the cached DataObject
3261 *
3262 * nPidlIndex=0 gets the fully qualified root path
3263 */
3264 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3265 {
3266
3267 STGMEDIUM medium;
3268 FORMATETC formatetc;
3269 LPITEMIDLIST pidl = NULL;
3270
3271 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3272
3273 if (!doSelected)
3274 return NULL;
3275
3276 /* Set the FORMATETC structure*/
3277 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3278
3279 /* Get the pidls from IDataObject */
3280 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3281 {
3282 LPIDA cida = GlobalLock(medium.u.hGlobal);
3283 if(nPidlIndex <= cida->cidl)
3284 {
3285 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3286 }
3287 COMCTL32_ReleaseStgMedium(medium);
3288 }
3289 return pidl;
3290 }
3291
3292 /***********************************************************************
3293 * GetNumSelected
3294 *
3295 * Return the number of selected items in the DataObject.
3296 *
3297 */
3298 UINT GetNumSelected( IDataObject *doSelected )
3299 {
3300 UINT retVal = 0;
3301 STGMEDIUM medium;
3302 FORMATETC formatetc;
3303
3304 TRACE("sv=%p\n", doSelected);
3305
3306 if (!doSelected) return 0;
3307
3308 /* Set the FORMATETC structure*/
3309 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3310
3311 /* Get the pidls from IDataObject */
3312 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3313 {
3314 LPIDA cida = GlobalLock(medium.u.hGlobal);
3315 retVal = cida->cidl;
3316 COMCTL32_ReleaseStgMedium(medium);
3317 return retVal;
3318 }
3319 return 0;
3320 }
3321
3322 /*
3323 * TOOLS
3324 */
3325
3326 /***********************************************************************
3327 * GetName
3328 *
3329 * Get the pidl's display name (relative to folder) and
3330 * put it in lpstrFileName.
3331 *
3332 * Return NOERROR on success,
3333 * E_FAIL otherwise
3334 */
3335
3336 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3337 {
3338 STRRET str;
3339 HRESULT hRes;
3340
3341 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3342
3343 if(!lpsf)
3344 {
3345 SHGetDesktopFolder(&lpsf);
3346 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3347 IShellFolder_Release(lpsf);
3348 return hRes;
3349 }
3350
3351 /* Get the display name of the pidl relative to the folder */
3352 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3353 {
3354 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3355 }
3356 return E_FAIL;
3357 }
3358
3359 /***********************************************************************
3360 * GetShellFolderFromPidl
3361 *
3362 * pidlRel is the item pidl relative
3363 * Return the IShellFolder of the absolute pidl
3364 */
3365 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3366 {
3367 IShellFolder *psf = NULL,*psfParent;
3368
3369 TRACE("%p\n", pidlAbs);
3370
3371 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3372 {
3373 psf = psfParent;
3374 if(pidlAbs && pidlAbs->mkid.cb)
3375 {
3376 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3377 {
3378 IShellFolder_Release(psfParent);
3379 return psf;
3380 }
3381 }
3382 /* return the desktop */
3383 return psfParent;
3384 }
3385 return NULL;
3386 }
3387
3388 /***********************************************************************
3389 * GetParentPidl
3390 *
3391 * Return the LPITEMIDLIST to the parent of the pidl in the list
3392 */
3393 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3394 {
3395 LPITEMIDLIST pidlParent;
3396
3397 TRACE("%p\n", pidl);
3398
3399 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3400 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3401
3402 return pidlParent;
3403 }
3404
3405 /***********************************************************************
3406 * GetPidlFromName
3407 *
3408 * returns the pidl of the file name relative to folder
3409 * NULL if an error occurred
3410 */
3411 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3412 {
3413 LPITEMIDLIST pidl = NULL;
3414 ULONG ulEaten;
3415
3416 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3417
3418 if(!lpcstrFileName) return NULL;
3419 if(!*lpcstrFileName) return NULL;
3420
3421 if(!lpsf)
3422 {
3423 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3424 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3425 IShellFolder_Release(lpsf);
3426 }
3427 }
3428 else
3429 {
3430 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3431 }
3432 return pidl;
3433 }
3434
3435 /*
3436 */
3437 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3438 {
3439 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3440 HRESULT ret;
3441
3442 TRACE("%p, %p\n", psf, pidl);
3443
3444 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3445
3446 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3447 /* see documentation shell 4.1*/
3448 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3449 }
3450
3451 /***********************************************************************
3452 * BrowseSelectedFolder
3453 */
3454 static BOOL BrowseSelectedFolder(HWND hwnd)
3455 {
3456 BOOL bBrowseSelFolder = FALSE;
3457 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3458
3459 TRACE("\n");
3460
3461 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3462 {
3463 LPITEMIDLIST pidlSelection;
3464
3465 /* get the file selected */
3466 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3467 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3468 {
3469 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3470 pidlSelection, SBSP_RELATIVE ) ) )
3471 {
3472 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3473 ' ','n','o','t',' ','e','x','i','s','t',0};
3474 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3475 }
3476 bBrowseSelFolder = TRUE;
3477 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3478 }
3479 COMDLG32_SHFree( pidlSelection );
3480 }
3481
3482 return bBrowseSelFolder;
3483 }
3484
3485 /*
3486 * Memory allocation methods */
3487 static void *MemAlloc(UINT size)
3488 {
3489 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3490 }
3491
3492 static void MemFree(void *mem)
3493 {
3494 HeapFree(GetProcessHeap(),0,mem);
3495 }
3496
3497 /*
3498 * Old-style (win3.1) dialogs */
3499
3500 /***********************************************************************
3501 * FD32_GetTemplate [internal]
3502 *
3503 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3504 * by a 32 bits application
3505 *
3506 */
3507 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3508 {
3509 LPOPENFILENAMEW ofnW = lfs->ofnW;
3510 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3511 HANDLE hDlgTmpl;
3512
3513 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3514 {
3515 if (!(lfs->template = LockResource( ofnW->hInstance )))
3516 {
3517 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3518 return FALSE;
3519 }
3520 }
3521 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3522 {
3523 HRSRC hResInfo;
3524 if (priv->ofnA)
3525 hResInfo = FindResourceA(priv->ofnA->hInstance,
3526 priv->ofnA->lpTemplateName,
3527 (LPSTR)RT_DIALOG);
3528 else
3529 hResInfo = FindResourceW(ofnW->hInstance,
3530 ofnW->lpTemplateName,
3531 (LPWSTR)RT_DIALOG);
3532 if (!hResInfo)
3533 {
3534 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3535 return FALSE;
3536 }
3537 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3538 hResInfo)) ||
3539 !(lfs->template = LockResource(hDlgTmpl)))
3540 {
3541 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3542 return FALSE;
3543 }
3544 } else { /* get it from internal Wine resource */
3545 HRSRC hResInfo;
3546 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3547 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3548 {
3549 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3550 return FALSE;
3551 }
3552 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3553 !(lfs->template = LockResource( hDlgTmpl )))
3554 {
3555 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3556 return FALSE;
3557 }
3558 }
3559 return TRUE;
3560 }
3561
3562
3563 /************************************************************************
3564 * FD32_Init [internal]
3565 * called from the common 16/32 code to initialize 32 bit data
3566 */
3567 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3568 {
3569 BOOL IsUnicode = (BOOL) data;
3570 PFD32_PRIVATE priv;
3571
3572 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3573 lfs->private1632 = priv;
3574 if (NULL == lfs->private1632) return FALSE;
3575 if (IsUnicode)
3576 {
3577 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3578 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3579 if (lfs->ofnW->lpfnHook)
3580 lfs->hook = TRUE;
3581 }
3582 else
3583 {
3584 priv->ofnA = (LPOPENFILENAMEA) lParam;
3585 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3586 if (priv->ofnA->lpfnHook)
3587 lfs->hook = TRUE;
3588 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3589 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3590 }
3591
3592 if (! FD32_GetTemplate(lfs)) return FALSE;
3593
3594 return TRUE;
3595 }
3596
3597 /***********************************************************************
3598 * FD32_CallWindowProc [internal]
3599 *
3600 * called from the common 16/32 code to call the appropriate hook
3601 */
3602 static BOOL CALLBACK FD32_CallWindowProc(const FD31_DATA *lfs, UINT wMsg, WPARAM wParam,
3603 LPARAM lParam)
3604 {
3605 BOOL ret;
3606 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3607
3608 if (priv->ofnA)
3609 {
3610 TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3611 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3612 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3613 TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3614 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3615 return ret;
3616 }
3617
3618 TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3619 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3620 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3621 TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3622 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3623 return ret;
3624 }
3625
3626 /***********************************************************************
3627 * FD32_UpdateResult [internal]
3628 * update the real client structures if any
3629 */
3630 static void CALLBACK FD32_UpdateResult(const FD31_DATA *lfs)
3631 {
3632 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3633 LPOPENFILENAMEW ofnW = lfs->ofnW;
3634
3635 if (priv->ofnA)
3636 {
3637 LPSTR lpszTemp;
3638 if (ofnW->nMaxFile &&
3639 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3640 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3641 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3642
3643 /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
3644 /* set filename offset */
3645 lpszTemp = PathFindFileNameA(priv->ofnA->lpstrFile);
3646 priv->ofnA->nFileOffset = (lpszTemp - priv->ofnA->lpstrFile);
3647
3648 /* set extension offset */
3649 lpszTemp = PathFindExtensionA(priv->ofnA->lpstrFile);
3650 priv->ofnA->nFileExtension = (*lpszTemp) ? (lpszTemp - priv->ofnA->lpstrFile) + 1 : 0;
3651 }
3652 }
3653
3654 /***********************************************************************
3655 * FD32_UpdateFileTitle [internal]
3656 * update the real client structures if any
3657 */
3658 static void CALLBACK FD32_UpdateFileTitle(const FD31_DATA *lfs)
3659 {
3660 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3661 LPOPENFILENAMEW ofnW = lfs->ofnW;
3662
3663 if (priv->ofnA)
3664 {
3665 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3666 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3667 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3668 }
3669 }
3670
3671
3672 /***********************************************************************
3673 * FD32_SendLbGetCurSel [internal]
3674 * retrieve selected listbox item
3675 */
3676 static LRESULT CALLBACK FD32_SendLbGetCurSel(const FD31_DATA *lfs)
3677 {
3678 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3679 }
3680
3681
3682 /************************************************************************
3683 * FD32_Destroy [internal]
3684 * called from the common 16/32 code to cleanup 32 bit data
3685 */
3686 static void CALLBACK FD32_Destroy(const FD31_DATA *lfs)
3687 {
3688 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3689
3690 /* if ofnW has been allocated, have to free everything in it */
3691 if (NULL != priv && NULL != priv->ofnA)
3692 {
3693 FD31_FreeOfnW(lfs->ofnW);
3694 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3695 }
3696 }
3697
3698 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3699 {
3700 callbacks->Init = FD32_Init;
3701 callbacks->CWP = FD32_CallWindowProc;
3702 callbacks->UpdateResult = FD32_UpdateResult;
3703 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3704 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3705 callbacks->Destroy = FD32_Destroy;
3706 }
3707
3708 /***********************************************************************
3709 * FD32_WMMeasureItem [internal]
3710 */
3711 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3712 {
3713 LPMEASUREITEMSTRUCT lpmeasure;
3714
3715 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3716 lpmeasure->itemHeight = FD31_GetFldrHeight();
3717 return TRUE;
3718 }
3719
3720
3721 /***********************************************************************
3722 * FileOpenDlgProc [internal]
3723 * Used for open and save, in fact.
3724 */
3725 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3726 WPARAM wParam, LPARAM lParam)
3727 {
3728 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3729
3730 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
3731 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3732 {
3733 INT_PTR lRet;
3734 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3735 if (lRet)
3736 return lRet; /* else continue message processing */
3737 }
3738 switch (wMsg)
3739 {
3740 case WM_INITDIALOG:
3741 return FD31_WMInitDialog(hWnd, wParam, lParam);
3742
3743 case WM_MEASUREITEM:
3744 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3745
3746 case WM_DRAWITEM:
3747 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3748
3749 case WM_COMMAND:
3750 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3751 #if 0
3752 case WM_CTLCOLOR:
3753 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3754 switch (HIWORD(lParam))
3755 {
3756 case CTLCOLOR_BTN:
3757 SetTextColor((HDC16)wParam, 0x00000000);
3758 return hGRAYBrush;
3759 case CTLCOLOR_STATIC:
3760 SetTextColor((HDC16)wParam, 0x00000000);
3761 return hGRAYBrush;
3762 }
3763 break;
3764 #endif
3765 }
3766 return FALSE;
3767 }
3768
3769
3770 /***********************************************************************
3771 * GetFileName31A [internal]
3772 *
3773 * Creates a win31 style dialog box for the user to select a file to open/save.
3774 */
3775 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
3776 UINT dlgType /* type dialogue : open/save */
3777 )
3778 {
3779 HINSTANCE hInst;
3780 BOOL bRet = FALSE;
3781 PFD31_DATA lfs;
3782 FD31_CALLBACKS callbacks;
3783
3784 if (!lpofn || !FD31_Init()) return FALSE;
3785
3786 TRACE("ofn flags %08x\n", lpofn->Flags);
3787 FD32_SetupCallbacks(&callbacks);
3788 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3789 if (lfs)
3790 {
3791 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3792 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3793 FD32_FileOpenDlgProc, (LPARAM)lfs);
3794 FD31_DestroyPrivate(lfs);
3795 }
3796
3797 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3798 return bRet;
3799 }
3800
3801 /***********************************************************************
3802 * GetFileName31W [internal]
3803 *
3804 * Creates a win31 style dialog box for the user to select a file to open/save
3805 */
3806 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
3807 UINT dlgType /* type dialogue : open/save */
3808 )
3809 {
3810 HINSTANCE hInst;
3811 BOOL bRet = FALSE;
3812 PFD31_DATA lfs;
3813 FD31_CALLBACKS callbacks;
3814
3815 if (!lpofn || !FD31_Init()) return FALSE;
3816
3817 FD32_SetupCallbacks(&callbacks);
3818 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3819 if (lfs)
3820 {
3821 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3822 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3823 FD32_FileOpenDlgProc, (LPARAM)lfs);
3824 FD31_DestroyPrivate(lfs);
3825 }
3826
3827 TRACE("file %s, file offset %d, ext offset %d\n",
3828 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3829 return bRet;
3830 }
3831
3832 /* ------------------ APIs ---------------------- */
3833
3834 /***********************************************************************
3835 * GetOpenFileNameA (COMDLG32.@)
3836 *
3837 * Creates a dialog box for the user to select a file to open.
3838 *
3839 * RETURNS
3840 * TRUE on success: user enters a valid file
3841 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3842 *
3843 */
3844 BOOL WINAPI GetOpenFileNameA(
3845 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3846 {
3847 BOOL win16look = FALSE;
3848
3849 TRACE("flags %08x\n", ofn->Flags);
3850
3851 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3852 if (ofn->Flags & OFN_FILEMUSTEXIST)
3853 ofn->Flags |= OFN_PATHMUSTEXIST;
3854
3855 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3856 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3857
3858 if (win16look)
3859 return GetFileName31A(ofn, OPEN_DIALOG);
3860 else
3861 return GetFileDialog95A(ofn, OPEN_DIALOG);
3862 }
3863
3864 /***********************************************************************
3865 * GetOpenFileNameW (COMDLG32.@)
3866 *
3867 * Creates a dialog box for the user to select a file to open.
3868 *
3869 * RETURNS
3870 * TRUE on success: user enters a valid file
3871 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3872 *
3873 */
3874 BOOL WINAPI GetOpenFileNameW(
3875 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3876 {
3877 BOOL win16look = FALSE;
3878
3879 TRACE("flags %08x\n", ofn->Flags);
3880
3881 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3882 if (ofn->Flags & OFN_FILEMUSTEXIST)
3883 ofn->Flags |= OFN_PATHMUSTEXIST;
3884
3885 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3886 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3887
3888 if (win16look)
3889 return GetFileName31W(ofn, OPEN_DIALOG);
3890 else
3891 return GetFileDialog95W(ofn, OPEN_DIALOG);
3892 }
3893
3894
3895 /***********************************************************************
3896 * GetSaveFileNameA (COMDLG32.@)
3897 *
3898 * Creates a dialog box for the user to select a file to save.
3899 *
3900 * RETURNS
3901 * TRUE on success: user enters a valid file
3902 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3903 *
3904 */
3905 BOOL WINAPI GetSaveFileNameA(
3906 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3907 {
3908 BOOL win16look = FALSE;
3909
3910 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3911 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3912
3913 if (win16look)
3914 return GetFileName31A(ofn, SAVE_DIALOG);
3915 else
3916 return GetFileDialog95A(ofn, SAVE_DIALOG);
3917 }
3918
3919 /***********************************************************************
3920 * GetSaveFileNameW (COMDLG32.@)
3921 *
3922 * Creates a dialog box for the user to select a file to save.
3923 *
3924 * RETURNS
3925 * TRUE on success: user enters a valid file
3926 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3927 *
3928 */
3929 BOOL WINAPI GetSaveFileNameW(
3930 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3931 {
3932 BOOL win16look = FALSE;
3933
3934 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3935 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3936
3937 if (win16look)
3938 return GetFileName31W(ofn, SAVE_DIALOG);
3939 else
3940 return GetFileDialog95W(ofn, SAVE_DIALOG);
3941 }
3942
3943 /***********************************************************************
3944 * GetFileTitleA (COMDLG32.@)
3945 *
3946 * See GetFileTitleW.
3947 */
3948 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
3949 {
3950 int ret;
3951 UNICODE_STRING strWFile;
3952 LPWSTR lpWTitle;
3953
3954 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
3955 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
3956 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
3957 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
3958 RtlFreeUnicodeString( &strWFile );
3959 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
3960 return ret;
3961 }
3962
3963
3964 /***********************************************************************
3965 * GetFileTitleW (COMDLG32.@)
3966 *
3967 * Get the name of a file.
3968 *
3969 * PARAMS
3970 * lpFile [I] name and location of file
3971 * lpTitle [O] returned file name
3972 * cbBuf [I] buffer size of lpTitle
3973 *
3974 * RETURNS
3975 * Success: zero
3976 * Failure: negative number.
3977 */
3978 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
3979 {
3980 int i, len;
3981 static const WCHAR brkpoint[] = {'*','[',']',0};
3982 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
3983
3984 if(lpFile == NULL || lpTitle == NULL)
3985 return -1;
3986
3987 len = lstrlenW(lpFile);
3988
3989 if (len == 0)
3990 return -1;
3991
3992 if(strpbrkW(lpFile, brkpoint))
3993 return -1;
3994
3995 len--;
3996
3997 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
3998 return -1;
3999
4000 for(i = len; i >= 0; i--)
4001 {
4002 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4003 {
4004 i++;
4005 break;
4006 }
4007 }
4008
4009 if(i == -1)
4010 i++;
4011
4012 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4013
4014 len = lstrlenW(lpFile+i)+1;
4015 if(cbBuf < len)
4016 return len;
4017
4018 lstrcpyW(lpTitle, &lpFile[i]);
4019 return 0;
4020 }