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