move from branch
[reactos.git] / reactos / dll / win32 / comdlg32 / filedlg.c
1 /*
2 * COMMDLG - File Open Dialogs Win95 look and feel
3 *
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 *
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
28 *
29 * FIXME: any hook gets a OPENFILENAMEA structure
30 *
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
32 *
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
34 *
35 * FIXME: algorithm for selecting the initial directory is too simple
36 *
37 * FIXME: add to recent docs
38 *
39 * FIXME: flags not implemented: OFN_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 <precomp.h>
53
54 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
55
56 #define UNIMPLEMENTED_FLAGS \
57 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
58 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
59 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
60 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
61
62 #define IsHooked(fodInfos) \
63 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
64 /***********************************************************************
65 * Data structure and global variables
66 */
67 typedef struct SFolder
68 {
69 int m_iImageIndex; /* Index of picture in image list */
70 HIMAGELIST hImgList;
71 int m_iIndent; /* Indentation index */
72 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
73
74 } SFOLDER,*LPSFOLDER;
75
76 typedef struct tagLookInInfo
77 {
78 int iMaxIndentation;
79 UINT uSelectedItem;
80 } LookInInfos;
81
82 typedef struct tagFD32_PRIVATE
83 {
84 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
85 } FD32_PRIVATE, *PFD32_PRIVATE;
86
87
88 /***********************************************************************
89 * Defines and global variables
90 */
91
92 /* Draw item constant */
93 #define ICONWIDTH 18
94 #define XTEXTOFFSET 3
95
96 /* AddItem flags*/
97 #define LISTEND -1
98
99 /* SearchItem methods */
100 #define SEARCH_PIDL 1
101 #define SEARCH_EXP 2
102 #define ITEM_NOTFOUND -1
103
104 /* Undefined windows message sent by CreateViewObject*/
105 #define WM_GETISHELLBROWSER WM_USER+7
106
107 /* NOTE
108 * Those macros exist in windowsx.h. However, you can't really use them since
109 * they rely on the UNICODE defines and can't be used inside Wine itself.
110 */
111
112 /* Combo box macros */
113 #define CBAddString(hwnd,str) \
114 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
115 #define CBAddStringW(hwnd,str) \
116 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
117
118 #define CBInsertString(hwnd,str,pos) \
119 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
120
121 #define CBDeleteString(hwnd,pos) \
122 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
123
124 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
125 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
126
127 #define CBGetItemDataPtr(hwnd,iItemId) \
128 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
129
130 #define CBGetLBText(hwnd,iItemId,str) \
131 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
132
133 #define CBGetCurSel(hwnd) \
134 SendMessageA(hwnd,CB_GETCURSEL,0,0);
135
136 #define CBSetCurSel(hwnd,pos) \
137 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
138
139 #define CBGetCount(hwnd) \
140 SendMessageA(hwnd,CB_GETCOUNT,0,0);
141 #define CBShowDropDown(hwnd,show) \
142 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
143 #define CBSetItemHeight(hwnd,index,height) \
144 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
145
146 #define CBSetExtendedUI(hwnd,flag) \
147 SendMessageA(hwnd,CB_SETEXTENDEDUI,(WPARAM)(flag),0)
148
149 const char *FileOpenDlgInfosStr = "FileOpenDlgInfos"; /* windows property description string */
150 const char *LookInInfosStr = "LookInInfos"; /* LOOKIN combo box property */
151
152 /***********************************************************************
153 * Prototypes
154 */
155
156 /* Internal functions used by the dialog */
157 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
158 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
159 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
160 BOOL FILEDLG95_OnOpen(HWND hwnd);
161 static LRESULT FILEDLG95_InitControls(HWND hwnd);
162 static void FILEDLG95_Clean(HWND hwnd);
163
164 /* Functions used by the shell navigation */
165 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
166 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
167 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
168 static void FILEDLG95_SHELL_Clean(HWND hwnd);
169 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
170
171 /* Functions used by the EDIT box */
172 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator);
173
174 /* Functions used by the filetype combo box */
175 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
176 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
177 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
178 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
179
180 /* Functions used by the Look In combo box */
181 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
182 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
183 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
184 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
185 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
186 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
187 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
188 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
189 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
190
191 /* Miscellaneous tool functions */
192 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
193 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
194 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
195 LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
196
197 /* Shell memory allocation */
198 static void *MemAlloc(UINT size);
199 static void MemFree(void *mem);
200
201 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
202 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode);
203 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
204 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
205 static BOOL BrowseSelectedFolder(HWND hwnd);
206
207 /***********************************************************************
208 * GetFileName95
209 *
210 * Creates an Open common dialog box that lets the user select
211 * the drive, directory, and the name of a file or set of files to open.
212 *
213 * IN : The FileOpenDlgInfos structure associated with the dialog
214 * OUT : TRUE on success
215 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
216 */
217 static BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
218 {
219
220 LRESULT lRes;
221 LPCVOID template;
222 HRSRC hRes;
223 HANDLE hDlgTmpl = 0;
224 HRESULT hr;
225
226 /* test for missing functionality */
227 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
228 {
229 FIXME("Flags 0x%08lx not yet implemented\n",
230 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
231 }
232
233 /* Create the dialog from a template */
234
235 if(!(hRes = FindResourceA(COMDLG32_hInstance,MAKEINTRESOURCEA(NEWFILEOPENORD),(LPSTR)RT_DIALOG)))
236 {
237 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
238 return FALSE;
239 }
240 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
241 !(template = LockResource( hDlgTmpl )))
242 {
243 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
244 return FALSE;
245 }
246
247 /* old style hook messages */
248 if (IsHooked(fodInfos))
249 {
250 fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
251 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
252 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
253 fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
254 }
255
256 /* Some shell namespace extensions depend on COM being initialized. */
257 hr = OleInitialize(NULL);
258
259 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
260 (LPDLGTEMPLATEA) template,
261 fodInfos->ofnInfos->hwndOwner,
262 FileOpenDlgProc95,
263 (LPARAM) fodInfos);
264 if (SUCCEEDED(hr))
265 OleUninitialize();
266
267 /* Unable to create the dialog */
268 if( lRes == -1)
269 return FALSE;
270
271 return lRes;
272 }
273
274 /***********************************************************************
275 * GetFileDialog95A
276 *
277 * Call GetFileName95 with this structure and clean the memory.
278 *
279 * IN : The OPENFILENAMEA initialisation structure passed to
280 * GetOpenFileNameA win api function (see filedlg.c)
281 */
282 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
283 {
284 BOOL ret;
285 FileOpenDlgInfos fodInfos;
286 LPSTR lpstrSavDir = NULL;
287 LPWSTR title = NULL;
288 LPWSTR defext = NULL;
289 LPWSTR filter = NULL;
290 LPWSTR customfilter = NULL;
291
292 /* Initialize FileOpenDlgInfos structure */
293 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
294
295 /* Pass in the original ofn */
296 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
297
298 /* save current directory */
299 if (ofn->Flags & OFN_NOCHANGEDIR)
300 {
301 lpstrSavDir = MemAlloc(MAX_PATH);
302 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
303 }
304
305 fodInfos.unicode = FALSE;
306
307 /* convert all the input strings to unicode */
308 if(ofn->lpstrInitialDir)
309 {
310 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
311 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
312 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
313 }
314 else
315 fodInfos.initdir = NULL;
316
317 if(ofn->lpstrFile)
318 {
319 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
320 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
321 }
322 else
323 fodInfos.filename = NULL;
324
325 if(ofn->lpstrDefExt)
326 {
327 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
328 defext = MemAlloc((len+1)*sizeof(WCHAR));
329 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
330 }
331 fodInfos.defext = defext;
332
333 if(ofn->lpstrTitle)
334 {
335 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
336 title = MemAlloc((len+1)*sizeof(WCHAR));
337 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
338 }
339 fodInfos.title = title;
340
341 if (ofn->lpstrFilter)
342 {
343 LPCSTR s;
344 int n, len;
345
346 /* filter is a list... title\0ext\0......\0\0 */
347 s = ofn->lpstrFilter;
348 while (*s) s = s+strlen(s)+1;
349 s++;
350 n = s - ofn->lpstrFilter;
351 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
352 filter = MemAlloc(len*sizeof(WCHAR));
353 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
354 }
355 fodInfos.filter = filter;
356
357 /* convert lpstrCustomFilter */
358 if (ofn->lpstrCustomFilter)
359 {
360 LPCSTR s;
361 int n, len;
362
363 /* customfilter contains a pair of strings... title\0ext\0 */
364 s = ofn->lpstrCustomFilter;
365 if (*s) s = s+strlen(s)+1;
366 if (*s) s = s+strlen(s)+1;
367 n = s - ofn->lpstrCustomFilter;
368 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
369 customfilter = MemAlloc(len*sizeof(WCHAR));
370 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
371 }
372 fodInfos.customfilter = customfilter;
373
374 /* Initialize the dialog property */
375 fodInfos.DlgInfos.dwDlgProp = 0;
376 fodInfos.DlgInfos.hwndCustomDlg = NULL;
377
378 switch(iDlgType)
379 {
380 case OPEN_DIALOG :
381 ret = GetFileName95(&fodInfos);
382 break;
383 case SAVE_DIALOG :
384 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
385 ret = GetFileName95(&fodInfos);
386 break;
387 default :
388 ret = 0;
389 }
390
391 if (lpstrSavDir)
392 {
393 SetCurrentDirectoryA(lpstrSavDir);
394 MemFree(lpstrSavDir);
395 }
396
397 if(title)
398 MemFree(title);
399 if(defext)
400 MemFree(defext);
401 if(filter)
402 MemFree(filter);
403 if(customfilter)
404 MemFree(customfilter);
405 if(fodInfos.initdir)
406 MemFree(fodInfos.initdir);
407
408 if(fodInfos.filename)
409 MemFree(fodInfos.filename);
410
411 TRACE("selected file: %s\n",ofn->lpstrFile);
412
413 return ret;
414 }
415
416 /***********************************************************************
417 * GetFileDialog95W
418 *
419 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
420 * Call GetFileName95 with this structure and clean the memory.
421 *
422 */
423 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
424 {
425 BOOL ret;
426 FileOpenDlgInfos fodInfos;
427 LPWSTR lpstrSavDir = NULL;
428
429 /* Initialize FileOpenDlgInfos structure */
430 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
431
432 /* Pass in the original ofn */
433 fodInfos.ofnInfos = ofn;
434
435 fodInfos.title = ofn->lpstrTitle;
436 fodInfos.defext = ofn->lpstrDefExt;
437 fodInfos.filter = ofn->lpstrFilter;
438 fodInfos.customfilter = ofn->lpstrCustomFilter;
439
440 /* convert string arguments, save others */
441 if(ofn->lpstrFile)
442 {
443 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
444 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
445 }
446 else
447 fodInfos.filename = NULL;
448
449 if(ofn->lpstrInitialDir)
450 {
451 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
452 DWORD len = strlenW(ofn->lpstrInitialDir)+1;
453 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
454 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
455 }
456 else
457 fodInfos.initdir = NULL;
458
459 /* save current directory */
460 if (ofn->Flags & OFN_NOCHANGEDIR)
461 {
462 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
463 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
464 }
465
466 fodInfos.unicode = TRUE;
467
468 switch(iDlgType)
469 {
470 case OPEN_DIALOG :
471 ret = GetFileName95(&fodInfos);
472 break;
473 case SAVE_DIALOG :
474 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
475 ret = GetFileName95(&fodInfos);
476 break;
477 default :
478 ret = 0;
479 }
480
481 if (lpstrSavDir)
482 {
483 SetCurrentDirectoryW(lpstrSavDir);
484 MemFree(lpstrSavDir);
485 }
486
487 /* restore saved IN arguments and convert OUT arguments back */
488 MemFree(fodInfos.filename);
489 MemFree(fodInfos.initdir);
490 return ret;
491 }
492
493 /******************************************************************************
494 * COMDLG32_GetDisplayNameOf [internal]
495 *
496 * Helper function to get the display name for a pidl.
497 */
498 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
499 LPSHELLFOLDER psfDesktop;
500 STRRET strret;
501
502 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
503 return FALSE;
504
505 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
506 IShellFolder_Release(psfDesktop);
507 return FALSE;
508 }
509
510 IShellFolder_Release(psfDesktop);
511 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
512 }
513
514 /***********************************************************************
515 * ArrangeCtrlPositions [internal]
516 *
517 * NOTE: Do not change anything here without a lot of testing.
518 */
519 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
520 {
521 HWND hwndChild, hwndStc32;
522 RECT rectParent, rectChild, rectStc32;
523 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
524
525 /* Take into account if open as read only checkbox and help button
526 * are hidden
527 */
528 if (hide_help)
529 {
530 RECT rectHelp, rectCancel;
531 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
532 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
533 /* subtract the height of the help button plus the space between
534 * the help button and the cancel button to the height of the dialog
535 */
536 help_fixup = rectHelp.bottom - rectCancel.bottom;
537 }
538
539 /*
540 There are two possibilities to add components to the default file dialog box.
541
542 By default, all the new components are added below the standard dialog box (the else case).
543
544 However, if there is a static text component with the stc32 id, a special case happens.
545 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
546 in the window and the cx and cy indicate how to size the window.
547 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
548 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
549
550 */
551
552 GetClientRect(hwndParentDlg, &rectParent);
553
554 /* when arranging controls we have to use fixed parent size */
555 rectParent.bottom -= help_fixup;
556
557 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
558 if (hwndStc32)
559 {
560 GetWindowRect(hwndStc32, &rectStc32);
561 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
562
563 /* set the size of the stc32 control according to the size of
564 * client area of the parent dialog
565 */
566 SetWindowPos(hwndStc32, 0,
567 0, 0,
568 rectParent.right, rectParent.bottom,
569 SWP_NOMOVE | SWP_NOZORDER);
570 }
571 else
572 SetRectEmpty(&rectStc32);
573
574 /* this part moves controls of the child dialog */
575 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
576 while (hwndChild)
577 {
578 if (hwndChild != hwndStc32)
579 {
580 GetWindowRect(hwndChild, &rectChild);
581 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
582
583 /* move only if stc32 exist */
584 if (hwndStc32 && rectChild.left > rectStc32.right)
585 {
586 LONG old_left = rectChild.left;
587
588 /* move to the right of visible controls of the parent dialog */
589 rectChild.left += rectParent.right;
590 rectChild.left -= rectStc32.right;
591
592 child_width_fixup = rectChild.left - old_left;
593 }
594 /* move even if stc32 doesn't exist */
595 if (rectChild.top >= rectStc32.bottom)
596 {
597 LONG old_top = rectChild.top;
598
599 /* move below visible controls of the parent dialog */
600 rectChild.top += rectParent.bottom;
601 rectChild.top -= rectStc32.bottom - rectStc32.top;
602
603 child_height_fixup = rectChild.top - old_top;
604 }
605
606 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
607 0, 0, SWP_NOSIZE | SWP_NOZORDER);
608 }
609 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
610 }
611
612 /* this part moves controls of the parent dialog */
613 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
614 while (hwndChild)
615 {
616 if (hwndChild != hwndChildDlg)
617 {
618 GetWindowRect(hwndChild, &rectChild);
619 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
620
621 /* left,top of stc32 marks the position of controls
622 * from the parent dialog
623 */
624 rectChild.left += rectStc32.left;
625 rectChild.top += rectStc32.top;
626
627 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
628 0, 0, SWP_NOSIZE | SWP_NOZORDER);
629 }
630 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
631 }
632
633 /* calculate the size of the resulting dialog */
634
635 /* here we have to use original parent size */
636 GetClientRect(hwndParentDlg, &rectParent);
637 GetClientRect(hwndChildDlg, &rectChild);
638
639 if (hwndStc32)
640 {
641 rectChild.right += child_width_fixup;
642 rectChild.bottom += child_height_fixup;
643
644 if (rectParent.right > rectChild.right)
645 {
646 rectParent.right += rectChild.right;
647 rectParent.right -= rectStc32.right - rectStc32.left;
648 }
649 else
650 {
651 rectParent.right = rectChild.right;
652 }
653
654 if (rectParent.bottom > rectChild.bottom)
655 {
656 rectParent.bottom += rectChild.bottom;
657 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
658 }
659 else
660 {
661 /* child dialog is higher, unconditionally set new dialog
662 * height to its size (help_fixup will be subtracted below)
663 */
664 rectParent.bottom = rectChild.bottom + help_fixup;
665 }
666 }
667 else
668 {
669 rectParent.bottom += rectChild.bottom;
670 }
671
672 /* finally use fixed parent size */
673 rectParent.bottom -= help_fixup;
674
675 /* set the size of the parent dialog */
676 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
677 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
678 SetWindowPos(hwndParentDlg, 0,
679 0, 0,
680 rectParent.right - rectParent.left,
681 rectParent.bottom - rectParent.top,
682 SWP_NOMOVE | SWP_NOZORDER);
683 }
684
685 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
686 {
687 switch(uMsg) {
688 case WM_INITDIALOG:
689 return TRUE;
690 }
691 return FALSE;
692 }
693
694 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
695 {
696 LPCVOID template;
697 HRSRC hRes;
698 HANDLE hDlgTmpl = 0;
699 HWND hChildDlg = 0;
700
701 TRACE("\n");
702
703 /*
704 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
705 * structure's hInstance parameter is not a HINSTANCE, but
706 * instead a pointer to a template resource to use.
707 */
708 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
709 {
710 HINSTANCE hinst;
711 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
712 {
713 hinst = COMDLG32_hInstance;
714 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
715 {
716 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
717 return NULL;
718 }
719 }
720 else
721 {
722 hinst = fodInfos->ofnInfos->hInstance;
723 if(fodInfos->unicode)
724 {
725 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
726 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
727 }
728 else
729 {
730 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
731 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
732 }
733 if (!hRes)
734 {
735 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
736 return NULL;
737 }
738 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
739 !(template = LockResource( hDlgTmpl )))
740 {
741 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
742 return NULL;
743 }
744 }
745 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
746 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
747 (LPARAM)fodInfos->ofnInfos);
748 if(hChildDlg)
749 {
750 ShowWindow(hChildDlg,SW_SHOW);
751 return hChildDlg;
752 }
753 }
754 else if( IsHooked(fodInfos))
755 {
756 RECT rectHwnd;
757 struct {
758 DLGTEMPLATE tmplate;
759 WORD menu,class,title;
760 } temp;
761 GetClientRect(hwnd,&rectHwnd);
762 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
763 temp.tmplate.dwExtendedStyle = 0;
764 temp.tmplate.cdit = 0;
765 temp.tmplate.x = 0;
766 temp.tmplate.y = 0;
767 temp.tmplate.cx = 0;
768 temp.tmplate.cy = 0;
769 temp.menu = temp.class = temp.title = 0;
770
771 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
772 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
773
774 return hChildDlg;
775 }
776 return NULL;
777 }
778
779 /***********************************************************************
780 * SendCustomDlgNotificationMessage
781 *
782 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
783 */
784
785 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
786 {
787 LRESULT hook_result = 0;
788
789 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
790
791 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
792
793 if(!fodInfos) return 0;
794
795 if(fodInfos->DlgInfos.hwndCustomDlg)
796 {
797 TRACE("CALL NOTIFY for %x\n", uCode);
798 if(fodInfos->unicode)
799 {
800 OFNOTIFYW ofnNotify;
801 ofnNotify.hdr.hwndFrom=hwndParentDlg;
802 ofnNotify.hdr.idFrom=0;
803 ofnNotify.hdr.code = uCode;
804 ofnNotify.lpOFN = fodInfos->ofnInfos;
805 ofnNotify.pszFile = NULL;
806 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
807 }
808 else
809 {
810 OFNOTIFYA ofnNotify;
811 ofnNotify.hdr.hwndFrom=hwndParentDlg;
812 ofnNotify.hdr.idFrom=0;
813 ofnNotify.hdr.code = uCode;
814 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
815 ofnNotify.pszFile = NULL;
816 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
817 }
818 TRACE("RET NOTIFY\n");
819 }
820 TRACE("Retval: 0x%08lx\n", hook_result);
821 return hook_result;
822 }
823
824 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer)
825 {
826 UINT sizeUsed = 0, n, total;
827 LPWSTR lpstrFileList = NULL;
828 WCHAR lpstrCurrentDir[MAX_PATH];
829 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
830
831 TRACE("CDM_GETFILEPATH:\n");
832
833 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
834 return -1;
835
836 /* get path and filenames */
837 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrCurrentDir);
838 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
839
840 TRACE("path >%s< filespec >%s< %d files\n",
841 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
842
843 if( fodInfos->unicode )
844 {
845 LPWSTR bufW = buffer;
846 total = strlenW(lpstrCurrentDir) + 1 + sizeUsed;
847
848 /* Prepend the current path */
849 n = strlenW(lpstrCurrentDir) + 1;
850 memcpy( bufW, lpstrCurrentDir, min(n,size) * sizeof(WCHAR));
851 if(n<size)
852 {
853 /* 'n' includes trailing \0 */
854 bufW[n-1] = '\\';
855 memcpy( &bufW[n], lpstrFileList, (size-n)*sizeof(WCHAR) );
856 }
857 TRACE("returned -> %s\n",debugstr_wn(bufW, total));
858 }
859 else
860 {
861 LPSTR bufA = buffer;
862 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
863 NULL, 0, NULL, NULL);
864 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
865 NULL, 0, NULL, NULL);
866
867 /* Prepend the current path */
868 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
869 bufA, size, NULL, NULL);
870
871 if(n<size)
872 {
873 /* 'n' includes trailing \0 */
874 bufA[n-1] = '\\';
875 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
876 &bufA[n], size-n, NULL, NULL);
877 }
878
879 TRACE("returned -> %s\n",debugstr_an(bufA, total));
880 }
881 MemFree(lpstrFileList);
882
883 return total;
884 }
885
886 static INT_PTR FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer)
887 {
888 UINT sizeUsed = 0;
889 LPWSTR lpstrFileList = NULL;
890 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
891
892 TRACE("CDM_GETSPEC:\n");
893
894 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
895 if( fodInfos->unicode )
896 {
897 LPWSTR bufW = buffer;
898 memcpy( bufW, lpstrFileList, sizeof(WCHAR)*sizeUsed );
899 }
900 else
901 {
902 LPSTR bufA = buffer;
903 sizeUsed = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed,
904 NULL, 0, NULL, NULL);
905 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
906 bufA, size, NULL, NULL);
907 }
908 MemFree(lpstrFileList);
909
910 return sizeUsed;
911 }
912
913 /***********************************************************************
914 * FILEDLG95_HandleCustomDialogMessages
915 *
916 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
917 */
918 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
919 {
920 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
921 WCHAR lpstrPath[MAX_PATH];
922 INT_PTR retval;
923
924 if(!fodInfos) return FALSE;
925
926 switch(uMsg)
927 {
928 case CDM_GETFILEPATH:
929 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
930 break;
931
932 case CDM_GETFOLDERPATH:
933 TRACE("CDM_GETFOLDERPATH:\n");
934 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
935 if (lParam)
936 {
937 if (fodInfos->unicode)
938 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
939 else
940 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
941 (LPSTR)lParam, (int)wParam, NULL, NULL);
942 }
943 retval = strlenW(lpstrPath);
944 break;
945
946 case CDM_GETSPEC:
947 retval = FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
948 break;
949
950 case CDM_SETCONTROLTEXT:
951 TRACE("CDM_SETCONTROLTEXT:\n");
952 if ( lParam )
953 {
954 if( fodInfos->unicode )
955 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
956 else
957 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
958 }
959 retval = TRUE;
960 break;
961
962 case CDM_HIDECONTROL:
963 /* MSDN states that it should fail for not OFN_EXPLORER case */
964 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
965 {
966 HWND control = GetDlgItem( hwnd, wParam );
967 if (control) ShowWindow( control, SW_HIDE );
968 retval = TRUE;
969 }
970 else retval = FALSE;
971 break;
972
973 default:
974 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
975 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
976 return FALSE;
977 }
978 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
979 return TRUE;
980 }
981
982 /***********************************************************************
983 * FileOpenDlgProc95
984 *
985 * File open dialog procedure
986 */
987 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
988 {
989 #if 0
990 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
991 #endif
992
993 switch(uMsg)
994 {
995 case WM_INITDIALOG:
996 {
997 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
998
999 /* Adds the FileOpenDlgInfos in the property list of the dialog
1000 so it will be easily accessible through a GetPropA(...) */
1001 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
1002
1003 fodInfos->DlgInfos.hwndCustomDlg =
1004 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1005
1006 FILEDLG95_InitControls(hwnd);
1007
1008 if (fodInfos->DlgInfos.hwndCustomDlg)
1009 {
1010 RECT rc;
1011 UINT flags = SWP_NOACTIVATE;
1012
1013 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1014 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1015
1016 /* resize the custom dialog to the parent size */
1017 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1018 GetClientRect(hwnd, &rc);
1019 else
1020 {
1021 /* our own fake template is zero sized and doesn't have
1022 * children, so there is no need to resize it.
1023 * Picasa depends on it.
1024 */
1025 flags |= SWP_NOSIZE;
1026 SetRectEmpty(&rc);
1027 }
1028 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1029 0, 0, rc.right, rc.bottom, flags);
1030 }
1031
1032 FILEDLG95_FillControls(hwnd, wParam, lParam);
1033
1034 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1035 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1036 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1037 return 0;
1038 }
1039 case WM_COMMAND:
1040 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1041 case WM_DRAWITEM:
1042 {
1043 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1044 {
1045 case IDC_LOOKIN:
1046 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1047 return TRUE;
1048 }
1049 }
1050 return FALSE;
1051
1052 case WM_GETISHELLBROWSER:
1053 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1054
1055 case WM_DESTROY:
1056 RemovePropA(hwnd, FileOpenDlgInfosStr);
1057 return FALSE;
1058
1059 case WM_NOTIFY:
1060 {
1061 LPNMHDR lpnmh = (LPNMHDR)lParam;
1062 UINT stringId = -1;
1063
1064 /* set up the button tooltips strings */
1065 if(TTN_GETDISPINFOA == lpnmh->code )
1066 {
1067 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1068 switch(lpnmh->idFrom )
1069 {
1070 /* Up folder button */
1071 case FCIDM_TB_UPFOLDER:
1072 stringId = IDS_UPFOLDER;
1073 break;
1074 /* New folder button */
1075 case FCIDM_TB_NEWFOLDER:
1076 stringId = IDS_NEWFOLDER;
1077 break;
1078 /* List option button */
1079 case FCIDM_TB_SMALLICON:
1080 stringId = IDS_LISTVIEW;
1081 break;
1082 /* Details option button */
1083 case FCIDM_TB_REPORTVIEW:
1084 stringId = IDS_REPORTVIEW;
1085 break;
1086 /* Desktop button */
1087 case FCIDM_TB_DESKTOP:
1088 stringId = IDS_TODESKTOP;
1089 break;
1090 default:
1091 stringId = 0;
1092 }
1093 lpdi->hinst = COMDLG32_hInstance;
1094 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1095 }
1096 return FALSE;
1097 }
1098 default :
1099 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1100 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1101 return FALSE;
1102 }
1103 }
1104
1105 /***********************************************************************
1106 * FILEDLG95_InitControls
1107 *
1108 * WM_INITDIALOG message handler (before hook notification)
1109 */
1110 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1111 {
1112 int win2000plus = 0;
1113 int win98plus = 0;
1114 int handledPath = FALSE;
1115 OSVERSIONINFOA osVi;
1116 static const WCHAR szwSlash[] = { '\\', 0 };
1117 static const WCHAR szwStar[] = { '*',0 };
1118
1119 TBBUTTON tbb[] =
1120 {
1121 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1122 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1123 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1124 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1125 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1126 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1127 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1128 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1129 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1130 };
1131 TBADDBITMAP tba[2];
1132 RECT rectTB;
1133 RECT rectlook;
1134 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1135
1136 tba[0].hInst = HINST_COMMCTRL;
1137 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1138 tba[1].hInst = COMDLG32_hInstance;
1139 tba[1].nID = 800;
1140
1141 TRACE("%p\n", fodInfos);
1142
1143 /* Get windows version emulating */
1144 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1145 GetVersionExA(&osVi);
1146 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1147 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1148 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1149 win2000plus = (osVi.dwMajorVersion > 4);
1150 if (win2000plus) win98plus = TRUE;
1151 }
1152 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1153
1154 /* Get the hwnd of the controls */
1155 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1156 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1157 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1158
1159 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1160 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1161
1162 /* construct the toolbar */
1163 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1164 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1165
1166 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1167 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1168 rectTB.left = rectlook.right;
1169 rectTB.top = rectlook.top-1;
1170
1171 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1172 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1173 rectTB.left, rectTB.top,
1174 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1175 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1176
1177 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1178
1179 /* FIXME: use TB_LOADIMAGES when implemented */
1180 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1181 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1182 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1183
1184 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1185 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1186
1187 /* Set the window text with the text specified in the OPENFILENAME structure */
1188 if(fodInfos->title)
1189 {
1190 SetWindowTextW(hwnd,fodInfos->title);
1191 }
1192 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1193 {
1194 WCHAR buf[16];
1195 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1196 SetWindowTextW(hwnd, buf);
1197 }
1198
1199 /* Initialise the file name edit control */
1200 handledPath = FALSE;
1201 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1202
1203 if(fodInfos->filename)
1204 {
1205 /* 1. If win2000 or higher and filename contains a path, use it
1206 in preference over the lpstrInitialDir */
1207 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1208 WCHAR tmpBuf[MAX_PATH];
1209 WCHAR *nameBit;
1210 DWORD result;
1211
1212 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1213 if (result) {
1214
1215 /* nameBit is always shorter than the original filename */
1216 strcpyW(fodInfos->filename,nameBit);
1217
1218 *nameBit = 0x00;
1219 if (fodInfos->initdir == NULL)
1220 MemFree(fodInfos->initdir);
1221 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1222 strcpyW(fodInfos->initdir, tmpBuf);
1223 handledPath = TRUE;
1224 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1225 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1226 }
1227 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1228
1229 } else {
1230 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1231 }
1232 }
1233
1234 /* 2. (All platforms) If initdir is not null, then use it */
1235 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1236 (*fodInfos->initdir!=0x00))
1237 {
1238 /* Work out the proper path as supplied one might be relative */
1239 /* (Here because supplying '.' as dir browses to My Computer) */
1240 if (handledPath==FALSE) {
1241 WCHAR tmpBuf[MAX_PATH];
1242 WCHAR tmpBuf2[MAX_PATH];
1243 WCHAR *nameBit;
1244 DWORD result;
1245
1246 strcpyW(tmpBuf, fodInfos->initdir);
1247 if( PathFileExistsW(tmpBuf) ) {
1248 /* initdir does not have to be a directory. If a file is
1249 * specified, the dir part is taken */
1250 if( PathIsDirectoryW(tmpBuf)) {
1251 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1252 strcatW(tmpBuf, szwSlash);
1253 }
1254 strcatW(tmpBuf, szwStar);
1255 }
1256 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1257 if (result) {
1258 *nameBit = 0x00;
1259 if (fodInfos->initdir)
1260 MemFree(fodInfos->initdir);
1261 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1262 strcpyW(fodInfos->initdir, tmpBuf2);
1263 handledPath = TRUE;
1264 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1265 }
1266 }
1267 else if (fodInfos->initdir)
1268 {
1269 MemFree(fodInfos->initdir);
1270 fodInfos->initdir = NULL;
1271 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1272 }
1273 }
1274 }
1275
1276 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1277 (*fodInfos->initdir==0x00)))
1278 {
1279 /* 3. All except w2k+: if filename contains a path use it */
1280 if (!win2000plus && fodInfos->filename &&
1281 *fodInfos->filename &&
1282 strpbrkW(fodInfos->filename, szwSlash)) {
1283 WCHAR tmpBuf[MAX_PATH];
1284 WCHAR *nameBit;
1285 DWORD result;
1286
1287 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1288 tmpBuf, &nameBit);
1289 if (result) {
1290 int len;
1291
1292 /* nameBit is always shorter than the original filename */
1293 strcpyW(fodInfos->filename, nameBit);
1294 *nameBit = 0x00;
1295
1296 len = strlenW(tmpBuf);
1297 if(fodInfos->initdir)
1298 MemFree(fodInfos->initdir);
1299 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1300 strcpyW(fodInfos->initdir, tmpBuf);
1301
1302 handledPath = TRUE;
1303 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1304 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1305 }
1306 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1307 }
1308
1309 /* 4. win98+ and win2000+ if any files of specified filter types in
1310 current directory, use it */
1311 if ( win98plus && handledPath == FALSE &&
1312 fodInfos->filter && *fodInfos->filter) {
1313
1314 BOOL searchMore = TRUE;
1315 LPCWSTR lpstrPos = fodInfos->filter;
1316 WIN32_FIND_DATAW FindFileData;
1317 HANDLE hFind;
1318
1319 while (searchMore)
1320 {
1321 /* filter is a list... title\0ext\0......\0\0 */
1322
1323 /* Skip the title */
1324 if(! *lpstrPos) break; /* end */
1325 lpstrPos += strlenW(lpstrPos) + 1;
1326
1327 /* See if any files exist in the current dir with this extension */
1328 if(! *lpstrPos) break; /* end */
1329
1330 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1331
1332 if (hFind == INVALID_HANDLE_VALUE) {
1333 /* None found - continue search */
1334 lpstrPos += strlenW(lpstrPos) + 1;
1335
1336 } else {
1337 searchMore = FALSE;
1338
1339 if(fodInfos->initdir)
1340 MemFree(fodInfos->initdir);
1341 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1342 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1343
1344 handledPath = TRUE;
1345 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1346 debugstr_w(lpstrPos));
1347 break;
1348 }
1349 }
1350 }
1351
1352 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1353
1354 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1355 if (handledPath == FALSE && (win2000plus || win98plus)) {
1356 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1357
1358 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1359 {
1360 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1361 {
1362 /* last fallback */
1363 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1364 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1365 } else {
1366 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1367 }
1368 } else {
1369 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1370 }
1371 handledPath = TRUE;
1372 } else if (handledPath==FALSE) {
1373 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1374 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1375 handledPath = TRUE;
1376 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1377 }
1378 }
1379 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1380 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1381
1382 /* Must the open as read only check box be checked ?*/
1383 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1384 {
1385 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1386 }
1387
1388 /* Must the open as read only check box be hidden? */
1389 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1390 {
1391 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1392 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1393 }
1394
1395 /* Must the help button be hidden? */
1396 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1397 {
1398 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1399 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1400 }
1401
1402 /* Resize the height, if open as read only checkbox ad help button
1403 are hidden and we are not using a custom template nor a customDialog
1404 */
1405 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1406 (!(fodInfos->ofnInfos->Flags &
1407 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1408 (!fodInfos->DlgInfos.hwndCustomDlg ))
1409 {
1410 RECT rectDlg, rectHelp, rectCancel;
1411 GetWindowRect(hwnd, &rectDlg);
1412 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1413 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1414 /* subtract the height of the help button plus the space between
1415 the help button and the cancel button to the height of the dialog */
1416 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1417 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1418 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1419 }
1420 /* change Open to Save */
1421 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1422 {
1423 WCHAR buf[16];
1424 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1425 SetDlgItemTextW(hwnd, IDOK, buf);
1426 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1427 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1428 }
1429 return 0;
1430 }
1431
1432 /***********************************************************************
1433 * FILEDLG95_FillControls
1434 *
1435 * WM_INITDIALOG message handler (after hook notification)
1436 */
1437 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1438 {
1439 LPITEMIDLIST pidlItemId = NULL;
1440
1441 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1442
1443 TRACE("dir=%s file=%s\n",
1444 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1445
1446 /* Get the initial directory pidl */
1447
1448 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1449 {
1450 WCHAR path[MAX_PATH];
1451
1452 GetCurrentDirectoryW(MAX_PATH,path);
1453 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1454 }
1455
1456 /* Initialise shell objects */
1457 FILEDLG95_SHELL_Init(hwnd);
1458
1459 /* Initialize the Look In combo box */
1460 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1461
1462 /* Initialize the filter combo box */
1463 FILEDLG95_FILETYPE_Init(hwnd);
1464
1465 /* Browse to the initial directory */
1466 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1467
1468 /* Free pidlItem memory */
1469 COMDLG32_SHFree(pidlItemId);
1470
1471 return TRUE;
1472 }
1473 /***********************************************************************
1474 * FILEDLG95_Clean
1475 *
1476 * Regroups all the cleaning functions of the filedlg
1477 */
1478 void FILEDLG95_Clean(HWND hwnd)
1479 {
1480 FILEDLG95_FILETYPE_Clean(hwnd);
1481 FILEDLG95_LOOKIN_Clean(hwnd);
1482 FILEDLG95_SHELL_Clean(hwnd);
1483 }
1484 /***********************************************************************
1485 * FILEDLG95_OnWMCommand
1486 *
1487 * WM_COMMAND message handler
1488 */
1489 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1490 {
1491 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1492 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1493 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1494
1495 switch(wID)
1496 {
1497 /* OK button */
1498 case IDOK:
1499 FILEDLG95_OnOpen(hwnd);
1500 break;
1501 /* Cancel button */
1502 case IDCANCEL:
1503 FILEDLG95_Clean(hwnd);
1504 EndDialog(hwnd, FALSE);
1505 break;
1506 /* Filetype combo box */
1507 case IDC_FILETYPE:
1508 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1509 break;
1510 /* LookIn combo box */
1511 case IDC_LOOKIN:
1512 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1513 break;
1514
1515 /* --- toolbar --- */
1516 /* Up folder button */
1517 case FCIDM_TB_UPFOLDER:
1518 FILEDLG95_SHELL_UpFolder(hwnd);
1519 break;
1520 /* New folder button */
1521 case FCIDM_TB_NEWFOLDER:
1522 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1523 break;
1524 /* List option button */
1525 case FCIDM_TB_SMALLICON:
1526 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1527 break;
1528 /* Details option button */
1529 case FCIDM_TB_REPORTVIEW:
1530 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1531 break;
1532 /* Details option button */
1533 case FCIDM_TB_DESKTOP:
1534 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1535 break;
1536
1537 case IDC_FILENAME:
1538 break;
1539
1540 }
1541 /* Do not use the listview selection anymore */
1542 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1543 return 0;
1544 }
1545
1546 /***********************************************************************
1547 * FILEDLG95_OnWMGetIShellBrowser
1548 *
1549 * WM_GETISHELLBROWSER message handler
1550 */
1551 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1552 {
1553
1554 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1555
1556 TRACE("\n");
1557
1558 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1559
1560 return TRUE;
1561 }
1562
1563
1564 /***********************************************************************
1565 * FILEDLG95_SendFileOK
1566 *
1567 * Sends the CDN_FILEOK notification if required
1568 *
1569 * RETURNS
1570 * TRUE if the dialog should close
1571 * FALSE if the dialog should not be closed
1572 */
1573 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1574 {
1575 /* ask the hook if we can close */
1576 if(IsHooked(fodInfos))
1577 {
1578 LRESULT retval;
1579
1580 TRACE("---\n");
1581 /* First send CDN_FILEOK as MSDN doc says */
1582 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1583 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1584 {
1585 TRACE("canceled\n");
1586 return (retval == 0);
1587 }
1588
1589 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1590 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1591 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1592 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1593 {
1594 TRACE("canceled\n");
1595 return (retval == 0);
1596 }
1597 }
1598 return TRUE;
1599 }
1600
1601 /***********************************************************************
1602 * FILEDLG95_OnOpenMultipleFiles
1603 *
1604 * Handles the opening of multiple files.
1605 *
1606 * FIXME
1607 * check destination buffer size
1608 */
1609 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1610 {
1611 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1612 UINT nCount, nSizePath;
1613 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1614
1615 TRACE("\n");
1616
1617 if(fodInfos->unicode)
1618 {
1619 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1620 ofn->lpstrFile[0] = '\0';
1621 }
1622 else
1623 {
1624 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1625 ofn->lpstrFile[0] = '\0';
1626 }
1627
1628 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1629
1630 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1631 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1632 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1633 {
1634 LPWSTR lpstrTemp = lpstrFileList;
1635
1636 for ( nCount = 0; nCount < nFileCount; nCount++ )
1637 {
1638 LPITEMIDLIST pidl;
1639
1640 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1641 if (!pidl)
1642 {
1643 WCHAR lpstrNotFound[100];
1644 WCHAR lpstrMsg[100];
1645 WCHAR tmp[400];
1646 static const WCHAR nl[] = {'\n',0};
1647
1648 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1649 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1650
1651 strcpyW(tmp, lpstrTemp);
1652 strcatW(tmp, nl);
1653 strcatW(tmp, lpstrNotFound);
1654 strcatW(tmp, nl);
1655 strcatW(tmp, lpstrMsg);
1656
1657 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1658 return FALSE;
1659 }
1660
1661 /* move to the next file in the list of files */
1662 lpstrTemp += strlenW(lpstrTemp) + 1;
1663 COMDLG32_SHFree(pidl);
1664 }
1665 }
1666
1667 nSizePath = strlenW(lpstrPathSpec) + 1;
1668 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1669 {
1670 /* For "oldstyle" dialog the components have to
1671 be separated by blanks (not '\0'!) and short
1672 filenames have to be used! */
1673 FIXME("Components have to be separated by blanks\n");
1674 }
1675 if(fodInfos->unicode)
1676 {
1677 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1678 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1679 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1680 }
1681 else
1682 {
1683 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1684
1685 if (ofn->lpstrFile != NULL)
1686 {
1687 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1688 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1689 if (ofn->nMaxFile > nSizePath)
1690 {
1691 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1692 ofn->lpstrFile + nSizePath,
1693 ofn->nMaxFile - nSizePath, NULL, NULL);
1694 }
1695 }
1696 }
1697
1698 fodInfos->ofnInfos->nFileOffset = nSizePath;
1699 fodInfos->ofnInfos->nFileExtension = 0;
1700
1701 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1702 return FALSE;
1703
1704 /* clean and exit */
1705 FILEDLG95_Clean(hwnd);
1706 return EndDialog(hwnd,TRUE);
1707 }
1708
1709 /***********************************************************************
1710 * FILEDLG95_OnOpen
1711 *
1712 * Ok button WM_COMMAND message handler
1713 *
1714 * If the function succeeds, the return value is nonzero.
1715 */
1716 #define ONOPEN_BROWSE 1
1717 #define ONOPEN_OPEN 2
1718 #define ONOPEN_SEARCH 3
1719 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1720 {
1721 WCHAR strMsgTitle[MAX_PATH];
1722 WCHAR strMsgText [MAX_PATH];
1723 if (idCaption)
1724 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1725 else
1726 strMsgTitle[0] = '\0';
1727 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1728 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1729 }
1730
1731 BOOL FILEDLG95_OnOpen(HWND hwnd)
1732 {
1733 LPWSTR lpstrFileList;
1734 UINT nFileCount = 0;
1735 UINT sizeUsed = 0;
1736 BOOL ret = TRUE;
1737 WCHAR lpstrPathAndFile[MAX_PATH];
1738 WCHAR lpstrTemp[MAX_PATH];
1739 LPSHELLFOLDER lpsf = NULL;
1740 int nOpenAction;
1741 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1742
1743 TRACE("hwnd=%p\n", hwnd);
1744
1745 /* get the files from the edit control */
1746 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1747
1748 /* try if the user selected a folder in the shellview */
1749 if(nFileCount == 0)
1750 {
1751 BrowseSelectedFolder(hwnd);
1752 return FALSE;
1753 }
1754
1755 if(nFileCount > 1)
1756 {
1757 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1758 goto ret;
1759 }
1760
1761 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1762
1763 /*
1764 Step 1: Build a complete path name from the current folder and
1765 the filename or path in the edit box.
1766 Special cases:
1767 - the path in the edit box is a root path
1768 (with or without drive letter)
1769 - the edit box contains ".." (or a path with ".." in it)
1770 */
1771
1772 /* Get the current directory name */
1773 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1774 {
1775 /* last fallback */
1776 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1777 }
1778 PathAddBackslashW(lpstrPathAndFile);
1779
1780 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1781
1782 /* if the user specifyed a fully qualified path use it */
1783 if(PathIsRelativeW(lpstrFileList))
1784 {
1785 strcatW(lpstrPathAndFile, lpstrFileList);
1786 }
1787 else
1788 {
1789 /* does the path have a drive letter? */
1790 if (PathGetDriveNumberW(lpstrFileList) == -1)
1791 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1792 else
1793 strcpyW(lpstrPathAndFile, lpstrFileList);
1794 }
1795
1796 /* resolve "." and ".." */
1797 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1798 strcpyW(lpstrPathAndFile, lpstrTemp);
1799 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1800
1801 MemFree(lpstrFileList);
1802
1803 /*
1804 Step 2: here we have a cleaned up path
1805
1806 We have to parse the path step by step to see if we have to browse
1807 to a folder if the path points to a directory or the last
1808 valid element is a directory.
1809
1810 valid variables:
1811 lpstrPathAndFile: cleaned up path
1812 */
1813
1814 if (nFileCount &&
1815 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1816 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1817 nOpenAction = ONOPEN_OPEN;
1818 else
1819 nOpenAction = ONOPEN_BROWSE;
1820
1821 /* don't apply any checks with OFN_NOVALIDATE */
1822 {
1823 LPWSTR lpszTemp, lpszTemp1;
1824 LPITEMIDLIST pidl = NULL;
1825 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1826
1827 /* check for invalid chars */
1828 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1829 {
1830 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1831 ret = FALSE;
1832 goto ret;
1833 }
1834
1835 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1836
1837 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1838 while (lpszTemp1)
1839 {
1840 LPSHELLFOLDER lpsfChild;
1841 WCHAR lpwstrTemp[MAX_PATH];
1842 DWORD dwEaten, dwAttributes;
1843 LPWSTR p;
1844
1845 strcpyW(lpwstrTemp, lpszTemp);
1846 p = PathFindNextComponentW(lpwstrTemp);
1847
1848 if (!p) break; /* end of path */
1849
1850 *p = 0;
1851 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1852
1853 /* There are no wildcards when OFN_NOVALIDATE is set */
1854 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1855 {
1856 static const WCHAR wszWild[] = { '*', '?', 0 };
1857 /* if the last element is a wildcard do a search */
1858 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1859 {
1860 nOpenAction = ONOPEN_SEARCH;
1861 break;
1862 }
1863 }
1864 lpszTemp1 = lpszTemp;
1865
1866 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1867
1868 /* append a backslash to drive letters */
1869 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1870 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1871 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1872 {
1873 PathAddBackslashW(lpwstrTemp);
1874 }
1875
1876 dwAttributes = SFGAO_FOLDER;
1877 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1878 {
1879 /* the path component is valid, we have a pidl of the next path component */
1880 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1881 if(dwAttributes & SFGAO_FOLDER)
1882 {
1883 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1884 {
1885 ERR("bind to failed\n"); /* should not fail */
1886 break;
1887 }
1888 IShellFolder_Release(lpsf);
1889 lpsf = lpsfChild;
1890 lpsfChild = NULL;
1891 }
1892 else
1893 {
1894 TRACE("value\n");
1895
1896 /* end dialog, return value */
1897 nOpenAction = ONOPEN_OPEN;
1898 break;
1899 }
1900 COMDLG32_SHFree(pidl);
1901 pidl = NULL;
1902 }
1903 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1904 {
1905 if(*lpszTemp) /* points to trailing null for last path element */
1906 {
1907 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1908 {
1909 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1910 break;
1911 }
1912 }
1913 else
1914 {
1915 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1916 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1917 {
1918 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1919 break;
1920 }
1921 }
1922 /* change to the current folder */
1923 nOpenAction = ONOPEN_OPEN;
1924 break;
1925 }
1926 else
1927 {
1928 nOpenAction = ONOPEN_OPEN;
1929 break;
1930 }
1931 }
1932 if(pidl) COMDLG32_SHFree(pidl);
1933 }
1934
1935 /*
1936 Step 3: here we have a cleaned up and validated path
1937
1938 valid variables:
1939 lpsf: ShellFolder bound to the rightmost valid path component
1940 lpstrPathAndFile: cleaned up path
1941 nOpenAction: action to do
1942 */
1943 TRACE("end validate sf=%p\n", lpsf);
1944
1945 switch(nOpenAction)
1946 {
1947 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1948 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1949 {
1950 int iPos;
1951 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1952 DWORD len;
1953
1954 /* replace the current filter */
1955 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1956 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1957 len = strlenW(lpszTemp)+1;
1958 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1959 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1960
1961 /* set the filter cb to the extension when possible */
1962 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1963 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1964 }
1965 /* fall through */
1966 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1967 TRACE("ONOPEN_BROWSE\n");
1968 {
1969 IPersistFolder2 * ppf2;
1970 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1971 {
1972 LPITEMIDLIST pidlCurrent;
1973 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1974 IPersistFolder2_Release(ppf2);
1975 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1976 {
1977 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1978 }
1979 else if( nOpenAction == ONOPEN_SEARCH )
1980 {
1981 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1982 }
1983 COMDLG32_SHFree(pidlCurrent);
1984 }
1985 }
1986 ret = FALSE;
1987 break;
1988 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
1989 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
1990 {
1991 WCHAR *ext = NULL;
1992
1993 /* update READONLY check box flag */
1994 if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
1995 fodInfos->ofnInfos->Flags |= OFN_READONLY;
1996 else
1997 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
1998
1999 /* Attach the file extension with file name*/
2000 ext = PathFindExtensionW(lpstrPathAndFile);
2001 if (! *ext)
2002 {
2003 /* if no extension is specified with file name, then */
2004 /* attach the extension from file filter or default one */
2005
2006 WCHAR *filterExt = NULL;
2007 LPWSTR lpstrFilter = NULL;
2008 static const WCHAR szwDot[] = {'.',0};
2009 int PathLength = strlenW(lpstrPathAndFile);
2010
2011 /* Attach the dot*/
2012 strcatW(lpstrPathAndFile, szwDot);
2013
2014 /*Get the file extension from file type filter*/
2015 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2016 fodInfos->ofnInfos->nFilterIndex-1);
2017
2018 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2019 filterExt = PathFindExtensionW(lpstrFilter);
2020
2021 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2022 strcatW(lpstrPathAndFile, filterExt + 1);
2023 else if ( fodInfos->defext ) /* attach the default file extension*/
2024 strcatW(lpstrPathAndFile, fodInfos->defext);
2025
2026 /* In Open dialog: if file does not exist try without extension */
2027 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2028 lpstrPathAndFile[PathLength] = '\0';
2029 }
2030
2031 if (fodInfos->defext) /* add default extension */
2032 {
2033 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2034 if (*ext)
2035 ext++;
2036 if (!lstrcmpiW(fodInfos->defext, ext))
2037 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2038 else
2039 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2040 }
2041
2042 /* In Save dialog: check if the file already exists */
2043 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2044 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2045 && PathFileExistsW(lpstrPathAndFile))
2046 {
2047 WCHAR lpstrOverwrite[100];
2048 int answer;
2049
2050 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2051 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2052 MB_YESNO | MB_ICONEXCLAMATION);
2053 if (answer == IDNO)
2054 {
2055 ret = FALSE;
2056 goto ret;
2057 }
2058 }
2059
2060 /* Check that the size of the file does not exceed buffer size.
2061 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2062 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2063 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2064 {
2065 LPWSTR lpszTemp;
2066
2067 /* fill destination buffer */
2068 if (fodInfos->ofnInfos->lpstrFile)
2069 {
2070 if(fodInfos->unicode)
2071 {
2072 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2073
2074 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2075 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2076 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2077 }
2078 else
2079 {
2080 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2081
2082 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2083 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2084 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2085 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2086 }
2087 }
2088
2089 /* set filename offset */
2090 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2091 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2092
2093 /* set extension offset */
2094 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2095 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2096
2097 /* set the lpstrFileTitle */
2098 if(fodInfos->ofnInfos->lpstrFileTitle)
2099 {
2100 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2101 if(fodInfos->unicode)
2102 {
2103 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2104 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2105 }
2106 else
2107 {
2108 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2109 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2110 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2111 }
2112 }
2113
2114 /* copy currently selected filter to lpstrCustomFilter */
2115 if (fodInfos->ofnInfos->lpstrCustomFilter)
2116 {
2117 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2118 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2119 NULL, 0, NULL, NULL);
2120 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2121 {
2122 LPSTR s = ofn->lpstrCustomFilter;
2123 s += strlen(ofn->lpstrCustomFilter)+1;
2124 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2125 s, len, NULL, NULL);
2126 }
2127 }
2128
2129
2130 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2131 goto ret;
2132
2133 TRACE("close\n");
2134 FILEDLG95_Clean(hwnd);
2135 ret = EndDialog(hwnd, TRUE);
2136 }
2137 else
2138 {
2139 WORD size;
2140
2141 size = strlenW(lpstrPathAndFile) + 1;
2142 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2143 size += 1;
2144 /* return needed size in first two bytes of lpstrFile */
2145 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2146 FILEDLG95_Clean(hwnd);
2147 ret = EndDialog(hwnd, FALSE);
2148 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2149 }
2150 goto ret;
2151 }
2152 break;
2153 }
2154
2155 ret:
2156 if(lpsf) IShellFolder_Release(lpsf);
2157 return ret;
2158 }
2159
2160 /***********************************************************************
2161 * FILEDLG95_SHELL_Init
2162 *
2163 * Initialisation of the shell objects
2164 */
2165 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2166 {
2167 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2168
2169 TRACE("\n");
2170
2171 /*
2172 * Initialisation of the FileOpenDialogInfos structure
2173 */
2174
2175 /* Shell */
2176
2177 /*ShellInfos */
2178 fodInfos->ShellInfos.hwndOwner = hwnd;
2179
2180 /* Disable multi-select if flag not set */
2181 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2182 {
2183 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2184 }
2185 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2186 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2187
2188 /* Construct the IShellBrowser interface */
2189 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2190
2191 return NOERROR;
2192 }
2193
2194 /***********************************************************************
2195 * FILEDLG95_SHELL_ExecuteCommand
2196 *
2197 * Change the folder option and refresh the view
2198 * If the function succeeds, the return value is nonzero.
2199 */
2200 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2201 {
2202 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2203
2204 IContextMenu * pcm;
2205 TRACE("(%p,%p)\n", hwnd, lpVerb);
2206
2207 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2208 SVGIO_BACKGROUND,
2209 &IID_IContextMenu,
2210 (LPVOID*)&pcm)))
2211 {
2212 CMINVOKECOMMANDINFO ci;
2213 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2214 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2215 ci.lpVerb = lpVerb;
2216 ci.hwnd = hwnd;
2217
2218 IContextMenu_InvokeCommand(pcm, &ci);
2219 IContextMenu_Release(pcm);
2220 }
2221
2222 return FALSE;
2223 }
2224
2225 /***********************************************************************
2226 * FILEDLG95_SHELL_UpFolder
2227 *
2228 * Browse to the specified object
2229 * If the function succeeds, the return value is nonzero.
2230 */
2231 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2232 {
2233 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2234
2235 TRACE("\n");
2236
2237 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2238 NULL,
2239 SBSP_PARENT)))
2240 {
2241 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2242 return TRUE;
2243 }
2244 return FALSE;
2245 }
2246
2247 /***********************************************************************
2248 * FILEDLG95_SHELL_BrowseToDesktop
2249 *
2250 * Browse to the Desktop
2251 * If the function succeeds, the return value is nonzero.
2252 */
2253 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2254 {
2255 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2256 LPITEMIDLIST pidl;
2257 HRESULT hres;
2258
2259 TRACE("\n");
2260
2261 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2262 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2263 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2264 COMDLG32_SHFree(pidl);
2265 return SUCCEEDED(hres);
2266 }
2267 /***********************************************************************
2268 * FILEDLG95_SHELL_Clean
2269 *
2270 * Cleans the memory used by shell objects
2271 */
2272 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2273 {
2274 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2275
2276 TRACE("\n");
2277
2278 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2279
2280 /* clean Shell interfaces */
2281 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2282 IShellView_Release(fodInfos->Shell.FOIShellView);
2283 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2284 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2285 if (fodInfos->Shell.FOIDataObject)
2286 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2287 }
2288
2289 /***********************************************************************
2290 * FILEDLG95_FILETYPE_Init
2291 *
2292 * Initialisation of the file type combo box
2293 */
2294 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2295 {
2296 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2297 int nFilters = 0; /* number of filters */
2298 int nFilterIndexCB;
2299
2300 TRACE("\n");
2301
2302 if(fodInfos->customfilter)
2303 {
2304 /* customfilter has one entry... title\0ext\0
2305 * Set first entry of combo box item with customfilter
2306 */
2307 LPWSTR lpstrExt;
2308 LPCWSTR lpstrPos = fodInfos->customfilter;
2309
2310 /* Get the title */
2311 lpstrPos += strlenW(fodInfos->customfilter) + 1;
2312
2313 /* Copy the extensions */
2314 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2315 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2316 strcpyW(lpstrExt,lpstrPos);
2317
2318 /* Add the item at the end of the combo */
2319 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2320 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2321 nFilters++;
2322 }
2323 if(fodInfos->filter)
2324 {
2325 LPCWSTR lpstrPos = fodInfos->filter;
2326
2327 for(;;)
2328 {
2329 /* filter is a list... title\0ext\0......\0\0
2330 * Set the combo item text to the title and the item data
2331 * to the ext
2332 */
2333 LPCWSTR lpstrDisplay;
2334 LPWSTR lpstrExt;
2335
2336 /* Get the title */
2337 if(! *lpstrPos) break; /* end */
2338 lpstrDisplay = lpstrPos;
2339 lpstrPos += strlenW(lpstrPos) + 1;
2340
2341 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2342
2343 nFilters++;
2344
2345 /* Copy the extensions */
2346 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2347 strcpyW(lpstrExt,lpstrPos);
2348 lpstrPos += strlenW(lpstrPos) + 1;
2349
2350 /* Add the item at the end of the combo */
2351 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2352
2353 /* malformed filters are added anyway... */
2354 if (!*lpstrExt) break;
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;