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