41dd83ffde082339bb0a64b68b9e2ebb212fd47c
[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 if(lstrlenW(lpwstrTemp)==2) PathAddBackslashW(lpwstrTemp);
1839
1840 dwAttributes = SFGAO_FOLDER;
1841 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1842 {
1843 /* the path component is valid, we have a pidl of the next path component */
1844 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1845 if(dwAttributes & SFGAO_FOLDER)
1846 {
1847 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1848 {
1849 ERR("bind to failed\n"); /* should not fail */
1850 break;
1851 }
1852 IShellFolder_Release(lpsf);
1853 lpsf = lpsfChild;
1854 lpsfChild = NULL;
1855 }
1856 else
1857 {
1858 TRACE("value\n");
1859
1860 /* end dialog, return value */
1861 nOpenAction = ONOPEN_OPEN;
1862 break;
1863 }
1864 COMDLG32_SHFree(pidl);
1865 pidl = NULL;
1866 }
1867 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1868 {
1869 if(*lpszTemp) /* points to trailing null for last path element */
1870 {
1871 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1872 {
1873 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1874 break;
1875 }
1876 }
1877 else
1878 {
1879 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1880 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1881 {
1882 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1883 break;
1884 }
1885 }
1886 /* change to the current folder */
1887 nOpenAction = ONOPEN_OPEN;
1888 break;
1889 }
1890 else
1891 {
1892 nOpenAction = ONOPEN_OPEN;
1893 break;
1894 }
1895 }
1896 if(pidl) COMDLG32_SHFree(pidl);
1897 }
1898
1899 /*
1900 Step 3: here we have a cleaned up and validated path
1901
1902 valid variables:
1903 lpsf: ShellFolder bound to the rightmost valid path component
1904 lpstrPathAndFile: cleaned up path
1905 nOpenAction: action to do
1906 */
1907 TRACE("end validate sf=%p\n", lpsf);
1908
1909 switch(nOpenAction)
1910 {
1911 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1912 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1913 {
1914 int iPos;
1915 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1916 DWORD len;
1917
1918 /* replace the current filter */
1919 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1920 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1921 len = strlenW(lpszTemp)+1;
1922 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1923 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1924
1925 /* set the filter cb to the extension when possible */
1926 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1927 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1928 }
1929 /* fall through */
1930 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1931 TRACE("ONOPEN_BROWSE\n");
1932 {
1933 IPersistFolder2 * ppf2;
1934 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1935 {
1936 LPITEMIDLIST pidlCurrent;
1937 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1938 IPersistFolder2_Release(ppf2);
1939 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1940 {
1941 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1942 }
1943 else if( nOpenAction == ONOPEN_SEARCH )
1944 {
1945 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1946 }
1947 COMDLG32_SHFree(pidlCurrent);
1948 }
1949 }
1950 ret = FALSE;
1951 break;
1952 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
1953 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
1954 {
1955 WCHAR *ext = NULL;
1956
1957 /* update READONLY check box flag */
1958 if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
1959 fodInfos->ofnInfos->Flags |= OFN_READONLY;
1960 else
1961 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
1962
1963 /* Attach the file extension with file name*/
1964 ext = PathFindExtensionW(lpstrPathAndFile);
1965 if (! *ext)
1966 {
1967 /* if no extension is specified with file name, then */
1968 /* attach the extension from file filter or default one */
1969
1970 WCHAR *filterExt = NULL;
1971 LPWSTR lpstrFilter = NULL;
1972 static const WCHAR szwDot[] = {'.',0};
1973 int PathLength = strlenW(lpstrPathAndFile);
1974
1975 /* Attach the dot*/
1976 strcatW(lpstrPathAndFile, szwDot);
1977
1978 /*Get the file extension from file type filter*/
1979 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
1980 fodInfos->ofnInfos->nFilterIndex-1);
1981
1982 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
1983 filterExt = PathFindExtensionW(lpstrFilter);
1984
1985 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
1986 strcatW(lpstrPathAndFile, filterExt + 1);
1987 else if ( fodInfos->defext ) /* attach the default file extension*/
1988 strcatW(lpstrPathAndFile, fodInfos->defext);
1989
1990 /* In Open dialog: if file does not exist try without extension */
1991 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
1992 lpstrPathAndFile[PathLength] = '\0';
1993 }
1994
1995 if (fodInfos->defext) /* add default extension */
1996 {
1997 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
1998 if (*ext)
1999 ext++;
2000 if (!lstrcmpiW(fodInfos->defext, ext))
2001 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2002 else
2003 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2004 }
2005
2006 /* In Save dialog: check if the file already exists */
2007 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2008 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2009 && PathFileExistsW(lpstrPathAndFile))
2010 {
2011 WCHAR lpstrOverwrite[100];
2012 int answer;
2013
2014 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2015 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2016 MB_YESNO | MB_ICONEXCLAMATION);
2017 if (answer == IDNO)
2018 {
2019 ret = FALSE;
2020 goto ret;
2021 }
2022 }
2023
2024 /* Check that the size of the file does not exceed buffer size.
2025 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2026 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2027 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2028 {
2029 LPWSTR lpszTemp;
2030
2031 /* fill destination buffer */
2032 if (fodInfos->ofnInfos->lpstrFile)
2033 {
2034 if(fodInfos->unicode)
2035 {
2036 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2037
2038 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2039 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2040 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2041 }
2042 else
2043 {
2044 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2045
2046 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2047 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2048 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2049 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2050 }
2051 }
2052
2053 /* set filename offset */
2054 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2055 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2056
2057 /* set extension offset */
2058 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2059 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2060
2061 /* set the lpstrFileTitle */
2062 if(fodInfos->ofnInfos->lpstrFileTitle)
2063 {
2064 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2065 if(fodInfos->unicode)
2066 {
2067 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2068 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2069 }
2070 else
2071 {
2072 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2073 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2074 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2075 }
2076 }
2077
2078 /* copy currently selected filter to lpstrCustomFilter */
2079 if (fodInfos->ofnInfos->lpstrCustomFilter)
2080 {
2081 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2082 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2083 NULL, 0, NULL, NULL);
2084 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2085 {
2086 LPSTR s = ofn->lpstrCustomFilter;
2087 s += strlen(ofn->lpstrCustomFilter)+1;
2088 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2089 s, len, NULL, NULL);
2090 }
2091 }
2092
2093
2094 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2095 goto ret;
2096
2097 TRACE("close\n");
2098 FILEDLG95_Clean(hwnd);
2099 ret = EndDialog(hwnd, TRUE);
2100 }
2101 else
2102 {
2103 WORD size;
2104
2105 size = strlenW(lpstrPathAndFile) + 1;
2106 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2107 size += 1;
2108 /* return needed size in first two bytes of lpstrFile */
2109 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2110 FILEDLG95_Clean(hwnd);
2111 ret = EndDialog(hwnd, FALSE);
2112 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2113 }
2114 goto ret;
2115 }
2116 break;
2117 }
2118
2119 ret:
2120 if(lpsf) IShellFolder_Release(lpsf);
2121 return ret;
2122 }
2123
2124 /***********************************************************************
2125 * FILEDLG95_SHELL_Init
2126 *
2127 * Initialisation of the shell objects
2128 */
2129 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2130 {
2131 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2132
2133 TRACE("\n");
2134
2135 /*
2136 * Initialisation of the FileOpenDialogInfos structure
2137 */
2138
2139 /* Shell */
2140
2141 /*ShellInfos */
2142 fodInfos->ShellInfos.hwndOwner = hwnd;
2143
2144 /* Disable multi-select if flag not set */
2145 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2146 {
2147 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2148 }
2149 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2150 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2151
2152 /* Construct the IShellBrowser interface */
2153 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2154
2155 return NOERROR;
2156 }
2157
2158 /***********************************************************************
2159 * FILEDLG95_SHELL_ExecuteCommand
2160 *
2161 * Change the folder option and refresh the view
2162 * If the function succeeds, the return value is nonzero.
2163 */
2164 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2165 {
2166 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2167
2168 IContextMenu * pcm;
2169 TRACE("(%p,%p)\n", hwnd, lpVerb);
2170
2171 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2172 SVGIO_BACKGROUND,
2173 &IID_IContextMenu,
2174 (LPVOID*)&pcm)))
2175 {
2176 CMINVOKECOMMANDINFO ci;
2177 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2178 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2179 ci.lpVerb = lpVerb;
2180 ci.hwnd = hwnd;
2181
2182 IContextMenu_InvokeCommand(pcm, &ci);
2183 IContextMenu_Release(pcm);
2184 }
2185
2186 return FALSE;
2187 }
2188
2189 /***********************************************************************
2190 * FILEDLG95_SHELL_UpFolder
2191 *
2192 * Browse to the specified object
2193 * If the function succeeds, the return value is nonzero.
2194 */
2195 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2196 {
2197 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2198
2199 TRACE("\n");
2200
2201 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2202 NULL,
2203 SBSP_PARENT)))
2204 {
2205 return TRUE;
2206 }
2207 return FALSE;
2208 }
2209
2210 /***********************************************************************
2211 * FILEDLG95_SHELL_BrowseToDesktop
2212 *
2213 * Browse to the Desktop
2214 * If the function succeeds, the return value is nonzero.
2215 */
2216 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2217 {
2218 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2219 LPITEMIDLIST pidl;
2220 HRESULT hres;
2221
2222 TRACE("\n");
2223
2224 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2225 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2226 COMDLG32_SHFree(pidl);
2227 return SUCCEEDED(hres);
2228 }
2229 /***********************************************************************
2230 * FILEDLG95_SHELL_Clean
2231 *
2232 * Cleans the memory used by shell objects
2233 */
2234 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2235 {
2236 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2237
2238 TRACE("\n");
2239
2240 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2241
2242 /* clean Shell interfaces */
2243 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2244 IShellView_Release(fodInfos->Shell.FOIShellView);
2245 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2246 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2247 if (fodInfos->Shell.FOIDataObject)
2248 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2249 }
2250
2251 /***********************************************************************
2252 * FILEDLG95_FILETYPE_Init
2253 *
2254 * Initialisation of the file type combo box
2255 */
2256 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2257 {
2258 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2259 int nFilters = 0; /* number of filters */
2260 int nFilterIndexCB;
2261
2262 TRACE("\n");
2263
2264 if(fodInfos->customfilter)
2265 {
2266 /* customfilter has one entry... title\0ext\0
2267 * Set first entry of combo box item with customfilter
2268 */
2269 LPWSTR lpstrExt;
2270 LPCWSTR lpstrPos = fodInfos->customfilter;
2271
2272 /* Get the title */
2273 lpstrPos += strlenW(fodInfos->customfilter) + 1;
2274
2275 /* Copy the extensions */
2276 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2277 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2278 strcpyW(lpstrExt,lpstrPos);
2279
2280 /* Add the item at the end of the combo */
2281 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2282 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2283 nFilters++;
2284 }
2285 if(fodInfos->filter)
2286 {
2287 LPCWSTR lpstrPos = fodInfos->filter;
2288
2289 for(;;)
2290 {
2291 /* filter is a list... title\0ext\0......\0\0
2292 * Set the combo item text to the title and the item data
2293 * to the ext
2294 */
2295 LPCWSTR lpstrDisplay;
2296 LPWSTR lpstrExt;
2297
2298 /* Get the title */
2299 if(! *lpstrPos) break; /* end */
2300 lpstrDisplay = lpstrPos;
2301 lpstrPos += strlenW(lpstrPos) + 1;
2302
2303 /* Copy the extensions */
2304 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2305 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2306 strcpyW(lpstrExt,lpstrPos);
2307 lpstrPos += strlenW(lpstrPos) + 1;
2308
2309 /* Add the item at the end of the combo */
2310 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2311 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2312 nFilters++;
2313 }
2314 }
2315
2316 /*
2317 * Set the current filter to the one specified
2318 * in the initialisation structure
2319 */
2320 if (fodInfos->filter || fodInfos->customfilter)
2321 {
2322 LPWSTR lpstrFilter;
2323
2324 /* Check to make sure our index isn't out of bounds. */
2325 if ( fodInfos->ofnInfos->nFilterIndex >
2326 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2327 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2328
2329 /* set default filter index */
2330 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2331 fodInfos->ofnInfos->nFilterIndex = 1;
2332
2333 /* calculate index of Combo Box item */
2334 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2335 if (fodInfos->customfilter == NULL)
2336 nFilterIndexCB--;
2337
2338 /* Set the current index selection. */
2339 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2340
2341 /* Get the corresponding text string from the combo box. */
2342 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2343 nFilterIndexCB);
2344
2345 if ((INT)lpstrFilter == CB_ERR) /* control is empty */
2346 lpstrFilter = NULL;
2347
2348 if(lpstrFilter)
2349 {
2350 DWORD len;
2351 CharLowerW(lpstrFilter); /* lowercase */
2352 len = strlenW(lpstrFilter)+1;
2353 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2354 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2355 }
2356 } else
2357 fodInfos->ofnInfos->nFilterIndex = 0;
2358
2359 return NOERROR;
2360 }
2361
2362 /***********************************************************************
2363 * FILEDLG95_FILETYPE_OnCommand
2364 *
2365 * WM_COMMAND of the file type combo box
2366 * If the function succeeds, the return value is nonzero.
2367 */
2368 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2369 {
2370 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2371
2372 switch(wNotifyCode)
2373 {
2374 case CBN_SELENDOK:
2375 {
2376 LPWSTR lpstrFilter;
2377
2378 /* Get the current item of the filetype combo box */
2379 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2380
2381 /* set the current filter index */
2382 fodInfos->ofnInfos->nFilterIndex = iItem +
2383 (fodInfos->customfilter == NULL ? 1 : 0);
2384
2385 /* Set the current filter with the current selection */
2386 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2387 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2388
2389 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2390 iItem);
2391 if((int)lpstrFilter != CB_ERR)
2392 {
2393 DWORD len;
2394 CharLowerW(lpstrFilter); /* lowercase */
2395 len = strlenW(lpstrFilter)+1;
2396 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2397 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2398 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2399 }
2400
2401 /* Refresh the actual view to display the included items*/
2402 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2403 }
2404 }
2405 return FALSE;
2406 }
2407 /***********************************************************************
2408 * FILEDLG95_FILETYPE_SearchExt
2409 *
2410 * searches for an extension in the filetype box
2411 */
2412 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2413 {
2414 int i, iCount = CBGetCount(hwnd);
2415
2416 TRACE("%s\n", debugstr_w(lpstrExt));
2417
2418 if(iCount != CB_ERR)
2419 {
2420 for(i=0;i<iCount;i++)
2421 {
2422 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2423 return i;
2424 }
2425 }
2426 return -1;
2427 }
2428
2429 /***********************************************************************
2430 * FILEDLG95_FILETYPE_Clean
2431 *
2432 * Clean the memory used by the filetype combo box
2433 */
2434 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2435 {
2436 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2437 int iPos;
2438 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2439
2440 TRACE("\n");
2441
2442 /* Delete each string of the combo and their associated data */
2443 if(iCount != CB_ERR)
2444 {
2445 for(iPos = iCount-1;iPos>=0;iPos--)
2446 {
2447 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2448 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2449 }
2450 }
2451 /* Current filter */
2452 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2453 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2454
2455 }
2456
2457 /***********************************************************************
2458 * FILEDLG95_LOOKIN_Init
2459 *
2460 * Initialisation of the look in combo box
2461 */
2462 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2463 {
2464 IShellFolder *psfRoot, *psfDrives;
2465 IEnumIDList *lpeRoot, *lpeDrives;
2466 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2467
2468 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2469
2470 TRACE("\n");
2471
2472 liInfos->iMaxIndentation = 0;
2473
2474 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2475
2476 /* set item height for both text field and listbox */
2477 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2478 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2479
2480 /* Turn on the extended UI for the combo box like Windows does */
2481 CBSetExtendedUI(hwndCombo, TRUE);
2482
2483 /* Initialise data of Desktop folder */
2484 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2485 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2486 COMDLG32_SHFree(pidlTmp);
2487
2488 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2489
2490 SHGetDesktopFolder(&psfRoot);
2491
2492 if (psfRoot)
2493 {
2494 /* enumerate the contents of the desktop */
2495 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2496 {
2497 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2498 {
2499 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2500
2501 /* special handling for CSIDL_DRIVES */
2502 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2503 {
2504 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2505 {
2506 /* enumerate the drives */
2507 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2508 {
2509 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2510 {
2511 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2512 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2513 COMDLG32_SHFree(pidlAbsTmp);
2514 COMDLG32_SHFree(pidlTmp1);
2515 }
2516 IEnumIDList_Release(lpeDrives);
2517 }
2518 IShellFolder_Release(psfDrives);
2519 }
2520 }
2521 COMDLG32_SHFree(pidlTmp);
2522 }
2523 IEnumIDList_Release(lpeRoot);
2524 }
2525 IShellFolder_Release(psfRoot);
2526 }
2527
2528 COMDLG32_SHFree(pidlDrives);
2529 return NOERROR;
2530 }
2531
2532 /***********************************************************************
2533 * FILEDLG95_LOOKIN_DrawItem
2534 *
2535 * WM_DRAWITEM message handler
2536 */
2537 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2538 {
2539 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2540 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2541 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2542 RECT rectText;
2543 RECT rectIcon;
2544 SHFILEINFOA sfi;
2545 HIMAGELIST ilItemImage;
2546 int iIndentation;
2547 TEXTMETRICA tm;
2548 LPSFOLDER tmpFolder;
2549
2550
2551 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2552
2553 TRACE("\n");
2554
2555 if(pDIStruct->itemID == -1)
2556 return 0;
2557
2558 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2559 pDIStruct->itemID)))
2560 return 0;
2561
2562
2563 if(pDIStruct->itemID == liInfos->uSelectedItem)
2564 {
2565 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2566 0,
2567 &sfi,
2568 sizeof (SHFILEINFOA),
2569 SHGFI_PIDL | SHGFI_SMALLICON |
2570 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2571 SHGFI_DISPLAYNAME );
2572 }
2573 else
2574 {
2575 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2576 0,
2577 &sfi,
2578 sizeof (SHFILEINFOA),
2579 SHGFI_PIDL | SHGFI_SMALLICON |
2580 SHGFI_SYSICONINDEX |
2581 SHGFI_DISPLAYNAME);
2582 }
2583
2584 /* Is this item selected ? */
2585 if(pDIStruct->itemState & ODS_SELECTED)
2586 {
2587 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2588 SetBkColor(pDIStruct->hDC,crHighLight);
2589 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2590 }
2591 else
2592 {
2593 SetTextColor(pDIStruct->hDC,crText);
2594 SetBkColor(pDIStruct->hDC,crWin);
2595 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2596 }
2597
2598 /* Do not indent item if drawing in the edit of the combo */
2599 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2600 {
2601 iIndentation = 0;
2602 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2603 0,
2604 &sfi,
2605 sizeof (SHFILEINFOA),
2606 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2607 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2608
2609 }
2610 else
2611 {
2612 iIndentation = tmpFolder->m_iIndent;
2613 }
2614 /* Draw text and icon */
2615
2616 /* Initialise the icon display area */
2617 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2618 rectIcon.top = pDIStruct->rcItem.top;
2619 rectIcon.right = rectIcon.left + ICONWIDTH;
2620 rectIcon.bottom = pDIStruct->rcItem.bottom;
2621
2622 /* Initialise the text display area */
2623 GetTextMetricsA(pDIStruct->hDC, &tm);
2624 rectText.left = rectIcon.right;
2625 rectText.top =
2626 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2627 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2628 rectText.bottom =
2629 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2630
2631 /* Draw the icon from the image list */
2632 ImageList_Draw(ilItemImage,
2633 sfi.iIcon,
2634 pDIStruct->hDC,
2635 rectIcon.left,
2636 rectIcon.top,
2637 ILD_TRANSPARENT );
2638
2639 /* Draw the associated text */
2640 if(sfi.szDisplayName)
2641 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2642
2643
2644 return NOERROR;
2645 }
2646
2647 /***********************************************************************
2648 * FILEDLG95_LOOKIN_OnCommand
2649 *
2650 * LookIn combo box WM_COMMAND message handler
2651 * If the function succeeds, the return value is nonzero.
2652 */
2653 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2654 {
2655 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2656
2657 TRACE("%p\n", fodInfos);
2658
2659 switch(wNotifyCode)
2660 {
2661 case CBN_SELENDOK:
2662 {
2663 LPSFOLDER tmpFolder;
2664 int iItem;
2665
2666 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2667
2668 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2669 iItem)))
2670 return FALSE;
2671
2672
2673 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2674 tmpFolder->pidlItem,
2675 SBSP_ABSOLUTE)))
2676 {
2677 return TRUE;
2678 }
2679 break;
2680 }
2681
2682 }
2683 return FALSE;
2684 }
2685
2686 /***********************************************************************
2687 * FILEDLG95_LOOKIN_AddItem
2688 *
2689 * Adds an absolute pidl item to the lookin combo box
2690 * returns the index of the inserted item
2691 */
2692 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2693 {
2694 LPITEMIDLIST pidlNext;
2695 SHFILEINFOA sfi;
2696 SFOLDER *tmpFolder;
2697 LookInInfos *liInfos;
2698
2699 TRACE("%08x\n", iInsertId);
2700
2701 if(!pidl)
2702 return -1;
2703
2704 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2705 return -1;
2706
2707 tmpFolder = MemAlloc(sizeof(SFOLDER));
2708 tmpFolder->m_iIndent = 0;
2709
2710 /* Calculate the indentation of the item in the lookin*/
2711 pidlNext = pidl;
2712 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2713 {
2714 tmpFolder->m_iIndent++;
2715 }
2716
2717 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2718
2719 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2720 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2721
2722 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2723 SHGetFileInfoA((LPSTR)pidl,
2724 0,
2725 &sfi,
2726 sizeof(sfi),
2727 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2728 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2729
2730 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2731
2732 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2733 {
2734 int iItemID;
2735
2736 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2737
2738 /* Add the item at the end of the list */
2739 if(iInsertId < 0)
2740 {
2741 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2742 }
2743 /* Insert the item at the iInsertId position*/
2744 else
2745 {
2746 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2747 }
2748
2749 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2750 return iItemID;
2751 }
2752
2753 COMDLG32_SHFree( tmpFolder->pidlItem );
2754 MemFree( tmpFolder );
2755 return -1;
2756
2757 }
2758
2759 /***********************************************************************
2760 * FILEDLG95_LOOKIN_InsertItemAfterParent
2761 *
2762 * Insert an item below its parent
2763 */
2764 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2765 {
2766
2767 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2768 int iParentPos;
2769
2770 TRACE("\n");
2771
2772 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2773
2774 if(iParentPos < 0)
2775 {
2776 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2777 }
2778
2779 /* Free pidlParent memory */
2780 COMDLG32_SHFree((LPVOID)pidlParent);
2781
2782 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2783 }
2784
2785 /***********************************************************************
2786 * FILEDLG95_LOOKIN_SelectItem
2787 *
2788 * Adds an absolute pidl item to the lookin combo box
2789 * returns the index of the inserted item
2790 */
2791 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2792 {
2793 int iItemPos;
2794 LookInInfos *liInfos;
2795
2796 TRACE("\n");
2797
2798 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2799
2800 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2801
2802 if(iItemPos < 0)
2803 {
2804 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2805 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2806 }
2807
2808 else
2809 {
2810 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2811 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2812 {
2813 int iRemovedItem;
2814
2815 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2816 break;
2817 if(iRemovedItem < iItemPos)
2818 iItemPos--;
2819 }
2820 }
2821
2822 CBSetCurSel(hwnd,iItemPos);
2823 liInfos->uSelectedItem = iItemPos;
2824
2825 return 0;
2826
2827 }
2828
2829 /***********************************************************************
2830 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2831 *
2832 * Remove the item with an expansion level over iExpansionLevel
2833 */
2834 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2835 {
2836 int iItemPos;
2837
2838 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2839
2840 TRACE("\n");
2841
2842 if(liInfos->iMaxIndentation <= 2)
2843 return -1;
2844
2845 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2846 {
2847 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2848 COMDLG32_SHFree(tmpFolder->pidlItem);
2849 MemFree(tmpFolder);
2850 CBDeleteString(hwnd,iItemPos);
2851 liInfos->iMaxIndentation--;
2852
2853 return iItemPos;
2854 }
2855
2856 return -1;
2857 }
2858
2859 /***********************************************************************
2860 * FILEDLG95_LOOKIN_SearchItem
2861 *
2862 * Search for pidl in the lookin combo box
2863 * returns the index of the found item
2864 */
2865 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2866 {
2867 int i = 0;
2868 int iCount = CBGetCount(hwnd);
2869
2870 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2871
2872 if (iCount != CB_ERR)
2873 {
2874 for(;i<iCount;i++)
2875 {
2876 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2877
2878 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2879 return i;
2880 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2881 return i;
2882 }
2883 }
2884
2885 return -1;
2886 }
2887
2888 /***********************************************************************
2889 * FILEDLG95_LOOKIN_Clean
2890 *
2891 * Clean the memory used by the lookin combo box
2892 */
2893 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2894 {
2895 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2896 int iPos;
2897 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2898
2899 TRACE("\n");
2900
2901 /* Delete each string of the combo and their associated data */
2902 if (iCount != CB_ERR)
2903 {
2904 for(iPos = iCount-1;iPos>=0;iPos--)
2905 {
2906 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
2907 COMDLG32_SHFree(tmpFolder->pidlItem);
2908 MemFree(tmpFolder);
2909 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
2910 }
2911 }
2912
2913 /* LookInInfos structure */
2914 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
2915
2916 }
2917 /***********************************************************************
2918 * FILEDLG95_FILENAME_FillFromSelection
2919 *
2920 * fills the edit box from the cached DataObject
2921 */
2922 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
2923 {
2924 FileOpenDlgInfos *fodInfos;
2925 LPITEMIDLIST pidl;
2926 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
2927 char lpstrTemp[MAX_PATH];
2928 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
2929
2930 TRACE("\n");
2931 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2932
2933 /* Count how many files we have */
2934 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
2935
2936 /* calculate the string length, count files */
2937 if (nFileSelected >= 1)
2938 {
2939 nLength += 3; /* first and last quotes, trailing \0 */
2940 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2941 {
2942 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2943
2944 if (pidl)
2945 {
2946 /* get the total length of the selected file names */
2947 lpstrTemp[0] = '\0';
2948 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2949
2950 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
2951 {
2952 nLength += strlen( lpstrTemp ) + 3;
2953 nFiles++;
2954 }
2955 COMDLG32_SHFree( pidl );
2956 }
2957 }
2958 }
2959
2960 /* allocate the buffer */
2961 if (nFiles <= 1) nLength = MAX_PATH;
2962 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
2963 lpstrAllFile[0] = '\0';
2964
2965 /* Generate the string for the edit control */
2966 if(nFiles >= 1)
2967 {
2968 lpstrCurrFile = lpstrAllFile;
2969 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2970 {
2971 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2972
2973 if (pidl)
2974 {
2975 /* get the file name */
2976 lpstrTemp[0] = '\0';
2977 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2978
2979 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
2980 {
2981 if ( nFiles > 1)
2982 {
2983 *lpstrCurrFile++ = '\"';
2984 strcpy( lpstrCurrFile, lpstrTemp );
2985 lpstrCurrFile += strlen( lpstrTemp );
2986 strcpy( lpstrCurrFile, "\" " );
2987 lpstrCurrFile += 2;
2988 }
2989 else
2990 {
2991 strcpy( lpstrAllFile, lpstrTemp );
2992 }
2993 }
2994 COMDLG32_SHFree( (LPVOID) pidl );
2995 }
2996 }
2997 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
2998
2999 /* Select the file name like Windows does */
3000 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
3001 }
3002 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3003 }
3004
3005
3006 /* copied from shell32 to avoid linking to it */
3007 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3008 {
3009 switch (src->uType)
3010 {
3011 case STRRET_WSTR:
3012 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
3013 COMDLG32_SHFree(src->u.pOleStr);
3014 break;
3015
3016 case STRRET_CSTR:
3017 lstrcpynA((LPSTR)dest, src->u.cStr, len);
3018 break;
3019
3020 case STRRET_OFFSET:
3021 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
3022 break;
3023
3024 default:
3025 FIXME("unknown type!\n");
3026 if (len)
3027 {
3028 *(LPSTR)dest = '\0';
3029 }
3030 return(FALSE);
3031 }
3032 return S_OK;
3033 }
3034
3035 /***********************************************************************
3036 * FILEDLG95_FILENAME_GetFileNames
3037 *
3038 * Copies the filenames to a delimited string list.
3039 * The delimiter is specified by the parameter 'separator',
3040 * usually either a space or a nul
3041 */
3042 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3043 {
3044 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3045 UINT nStrCharCount = 0; /* index in src buffer */
3046 UINT nFileIndex = 0; /* index in dest buffer */
3047 UINT nFileCount = 0; /* number of files */
3048 UINT nStrLen = 0; /* length of string in edit control */
3049 LPWSTR lpstrEdit; /* buffer for string from edit control */
3050
3051 TRACE("\n");
3052
3053 /* get the filenames from the edit control */
3054 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3055 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3056 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3057
3058 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3059
3060 /* we might get single filename without any '"',
3061 * so we need nStrLen + terminating \0 + end-of-list \0 */
3062 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3063 *sizeUsed = 0;
3064
3065 /* build delimited file list from filenames */
3066 while ( nStrCharCount <= nStrLen )
3067 {
3068 if ( lpstrEdit[nStrCharCount]=='"' )
3069 {
3070 nStrCharCount++;
3071 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3072 {
3073 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3074 (*sizeUsed)++;
3075 nStrCharCount++;
3076 }
3077 (*lpstrFileList)[nFileIndex++] = separator;
3078 (*sizeUsed)++;
3079 nFileCount++;
3080 }
3081 nStrCharCount++;
3082 }
3083
3084 /* single, unquoted string */
3085 if ((nStrLen > 0) && (*sizeUsed == 0) )
3086 {
3087 strcpyW(*lpstrFileList, lpstrEdit);
3088 nFileIndex = strlenW(lpstrEdit) + 1;
3089 (*sizeUsed) = nFileIndex;
3090 nFileCount = 1;
3091 }
3092
3093 /* trailing \0 */
3094 (*lpstrFileList)[nFileIndex] = '\0';
3095 (*sizeUsed)++;
3096
3097 MemFree(lpstrEdit);
3098 return nFileCount;
3099 }
3100
3101 #define SETDefFormatEtc(fe,cf,med) \
3102 { \
3103 (fe).cfFormat = cf;\
3104 (fe).dwAspect = DVASPECT_CONTENT; \
3105 (fe).ptd =NULL;\
3106 (fe).tymed = med;\
3107 (fe).lindex = -1;\
3108 };
3109
3110 /*
3111 * DATAOBJECT Helper functions
3112 */
3113
3114 /***********************************************************************
3115 * COMCTL32_ReleaseStgMedium
3116 *
3117 * like ReleaseStgMedium from ole32
3118 */
3119 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3120 {
3121 if(medium.pUnkForRelease)
3122 {
3123 IUnknown_Release(medium.pUnkForRelease);
3124 }
3125 else
3126 {
3127 GlobalUnlock(medium.u.hGlobal);
3128 GlobalFree(medium.u.hGlobal);
3129 }
3130 }
3131
3132 /***********************************************************************
3133 * GetPidlFromDataObject
3134 *
3135 * Return pidl(s) by number from the cached DataObject
3136 *
3137 * nPidlIndex=0 gets the fully qualified root path
3138 */
3139 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3140 {
3141
3142 STGMEDIUM medium;
3143 FORMATETC formatetc;
3144 LPITEMIDLIST pidl = NULL;
3145
3146 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3147
3148 /* Set the FORMATETC structure*/
3149 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3150
3151 /* Get the pidls from IDataObject */
3152 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3153 {
3154 LPIDA cida = GlobalLock(medium.u.hGlobal);
3155 if(nPidlIndex <= cida->cidl)
3156 {
3157 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3158 }
3159 COMCTL32_ReleaseStgMedium(medium);
3160 }
3161 return pidl;
3162 }
3163
3164 /***********************************************************************
3165 * GetNumSelected
3166 *
3167 * Return the number of selected items in the DataObject.
3168 *
3169 */
3170 UINT GetNumSelected( IDataObject *doSelected )
3171 {
3172 UINT retVal = 0;
3173 STGMEDIUM medium;
3174 FORMATETC formatetc;
3175
3176 TRACE("sv=%p\n", doSelected);
3177
3178 if (!doSelected) return 0;
3179
3180 /* Set the FORMATETC structure*/
3181 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3182
3183 /* Get the pidls from IDataObject */
3184 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3185 {
3186 LPIDA cida = GlobalLock(medium.u.hGlobal);
3187 retVal = cida->cidl;
3188 COMCTL32_ReleaseStgMedium(medium);
3189 return retVal;
3190 }
3191 return 0;
3192 }
3193
3194 /*
3195 * TOOLS
3196 */
3197
3198 /***********************************************************************
3199 * GetName
3200 *
3201 * Get the pidl's display name (relative to folder) and
3202 * put it in lpstrFileName.
3203 *
3204 * Return NOERROR on success,
3205 * E_FAIL otherwise
3206 */
3207
3208 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3209 {
3210 STRRET str;
3211 HRESULT hRes;
3212
3213 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3214
3215 if(!lpsf)
3216 {
3217 SHGetDesktopFolder(&lpsf);
3218 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3219 IShellFolder_Release(lpsf);
3220 return hRes;
3221 }
3222
3223 /* Get the display name of the pidl relative to the folder */
3224 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3225 {
3226 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3227 }
3228 return E_FAIL;
3229 }
3230
3231 /***********************************************************************
3232 * GetShellFolderFromPidl
3233 *
3234 * pidlRel is the item pidl relative
3235 * Return the IShellFolder of the absolute pidl
3236 */
3237 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3238 {
3239 IShellFolder *psf = NULL,*psfParent;
3240
3241 TRACE("%p\n", pidlAbs);
3242
3243 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3244 {
3245 psf = psfParent;
3246 if(pidlAbs && pidlAbs->mkid.cb)
3247 {
3248 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3249 {
3250 IShellFolder_Release(psfParent);
3251 return psf;
3252 }
3253 }
3254 /* return the desktop */
3255 return psfParent;
3256 }
3257 return NULL;
3258 }
3259
3260 /***********************************************************************
3261 * GetParentPidl
3262 *
3263 * Return the LPITEMIDLIST to the parent of the pidl in the list
3264 */
3265 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3266 {
3267 LPITEMIDLIST pidlParent;
3268
3269 TRACE("%p\n", pidl);
3270
3271 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3272 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3273
3274 return pidlParent;
3275 }
3276
3277 /***********************************************************************
3278 * GetPidlFromName
3279 *
3280 * returns the pidl of the file name relative to folder
3281 * NULL if an error occurred
3282 */
3283 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3284 {
3285 LPITEMIDLIST pidl = NULL;
3286 ULONG ulEaten;
3287
3288 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3289
3290 if(!lpcstrFileName) return NULL;
3291 if(!*lpcstrFileName) return NULL;
3292
3293 if(!lpsf)
3294 {
3295 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3296 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3297 IShellFolder_Release(lpsf);
3298 }
3299 }
3300 else
3301 {
3302 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3303 }
3304 return pidl;
3305 }
3306
3307 /*
3308 */
3309 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3310 {
3311 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3312 HRESULT ret;
3313
3314 TRACE("%p, %p\n", psf, pidl);
3315
3316 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3317
3318 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3319 /* see documentation shell 4.1*/
3320 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3321 }
3322
3323 /***********************************************************************
3324 * BrowseSelectedFolder
3325 */
3326 static BOOL BrowseSelectedFolder(HWND hwnd)
3327 {
3328 BOOL bBrowseSelFolder = FALSE;
3329 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3330
3331 TRACE("\n");
3332
3333 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3334 {
3335 LPITEMIDLIST pidlSelection;
3336
3337 /* get the file selected */
3338 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3339 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3340 {
3341 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3342 pidlSelection, SBSP_RELATIVE ) ) )
3343 {
3344 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3345 ' ','n','o','t',' ','e','x','i','s','t',0};
3346 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3347 }
3348
3349 bBrowseSelFolder = TRUE;
3350 }
3351 COMDLG32_SHFree( pidlSelection );
3352 }
3353
3354 return bBrowseSelFolder;
3355 }
3356
3357 /*
3358 * Memory allocation methods */
3359 static void *MemAlloc(UINT size)
3360 {
3361 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3362 }
3363
3364 static void MemFree(void *mem)
3365 {
3366 HeapFree(GetProcessHeap(),0,mem);
3367 }
3368
3369 /*
3370 * Old-style (win3.1) dialogs */
3371
3372 /***********************************************************************
3373 * FD32_GetTemplate [internal]
3374 *
3375 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3376 * by a 32 bits application
3377 *
3378 */
3379 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3380 {
3381 LPOPENFILENAMEW ofnW = lfs->ofnW;
3382 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3383 HANDLE hDlgTmpl;
3384
3385 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3386 {
3387 if (!(lfs->template = LockResource( ofnW->hInstance )))
3388 {
3389 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3390 return FALSE;
3391 }
3392 }
3393 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3394 {
3395 HRSRC hResInfo;
3396 if (priv->ofnA)
3397 hResInfo = FindResourceA(priv->ofnA->hInstance,
3398 priv->ofnA->lpTemplateName,
3399 (LPSTR)RT_DIALOG);
3400 else
3401 hResInfo = FindResourceW(ofnW->hInstance,
3402 ofnW->lpTemplateName,
3403 (LPWSTR)RT_DIALOG);
3404 if (!hResInfo)
3405 {
3406 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3407 return FALSE;
3408 }
3409 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3410 hResInfo)) ||
3411 !(lfs->template = LockResource(hDlgTmpl)))
3412 {
3413 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3414 return FALSE;
3415 }
3416 } else { /* get it from internal Wine resource */
3417 HRSRC hResInfo;
3418 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3419 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3420 {
3421 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3422 return FALSE;
3423 }
3424 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3425 !(lfs->template = LockResource( hDlgTmpl )))
3426 {
3427 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3428 return FALSE;
3429 }
3430 }
3431 return TRUE;
3432 }
3433
3434
3435 /************************************************************************
3436 * FD32_Init [internal]
3437 * called from the common 16/32 code to initialize 32 bit data
3438 */
3439 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3440 {
3441 BOOL IsUnicode = (BOOL) data;
3442 PFD32_PRIVATE priv;
3443
3444 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3445 lfs->private1632 = priv;
3446 if (NULL == lfs->private1632) return FALSE;
3447 if (IsUnicode)
3448 {
3449 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3450 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3451 if (lfs->ofnW->lpfnHook)
3452 lfs->hook = TRUE;
3453 }
3454 else
3455 {
3456 priv->ofnA = (LPOPENFILENAMEA) lParam;
3457 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3458 if (priv->ofnA->lpfnHook)
3459 lfs->hook = TRUE;
3460 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3461 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3462 }
3463
3464 if (! FD32_GetTemplate(lfs)) return FALSE;
3465
3466 return TRUE;
3467 }
3468
3469 /***********************************************************************
3470 * FD32_CallWindowProc [internal]
3471 *
3472 * called from the common 16/32 code to call the appropriate hook
3473 */
3474 BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
3475 LPARAM lParam)
3476 {
3477 BOOL ret;
3478 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3479
3480 if (priv->ofnA)
3481 {
3482 TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3483 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3484 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3485 TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3486 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3487 return ret;
3488 }
3489
3490 TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3491 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3492 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3493 TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3494 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3495 return ret;
3496 }
3497
3498 /***********************************************************************
3499 * FD32_UpdateResult [internal]
3500 * update the real client structures if any
3501 */
3502 static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs)
3503 {
3504 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3505 LPOPENFILENAMEW ofnW = lfs->ofnW;
3506
3507 if (priv->ofnA)
3508 {
3509 if (ofnW->nMaxFile &&
3510 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3511 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3512 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3513 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3514 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3515 }
3516 }
3517
3518 /***********************************************************************
3519 * FD32_UpdateFileTitle [internal]
3520 * update the real client structures if any
3521 */
3522 static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs)
3523 {
3524 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3525 LPOPENFILENAMEW ofnW = lfs->ofnW;
3526
3527 if (priv->ofnA)
3528 {
3529 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3530 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3531 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3532 }
3533 }
3534
3535
3536 /***********************************************************************
3537 * FD32_SendLbGetCurSel [internal]
3538 * retrieve selected listbox item
3539 */
3540 static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs)
3541 {
3542 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3543 }
3544
3545
3546 /************************************************************************
3547 * FD32_Destroy [internal]
3548 * called from the common 16/32 code to cleanup 32 bit data
3549 */
3550 static void CALLBACK FD32_Destroy(PFD31_DATA lfs)
3551 {
3552 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3553
3554 /* if ofnW has been allocated, have to free everything in it */
3555 if (NULL != priv && NULL != priv->ofnA)
3556 {
3557 FD31_FreeOfnW(lfs->ofnW);
3558 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3559 }
3560 }
3561
3562 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3563 {
3564 callbacks->Init = FD32_Init;
3565 callbacks->CWP = FD32_CallWindowProc;
3566 callbacks->UpdateResult = FD32_UpdateResult;
3567 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3568 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3569 callbacks->Destroy = FD32_Destroy;
3570 }
3571
3572 /***********************************************************************
3573 * FD32_WMMeasureItem [internal]
3574 */
3575 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3576 {
3577 LPMEASUREITEMSTRUCT lpmeasure;
3578
3579 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3580 lpmeasure->itemHeight = FD31_GetFldrHeight();
3581 return TRUE;
3582 }
3583
3584
3585 /***********************************************************************
3586 * FileOpenDlgProc [internal]
3587 * Used for open and save, in fact.
3588 */
3589 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3590 WPARAM wParam, LPARAM lParam)
3591 {
3592 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3593
3594 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
3595 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3596 {
3597 INT_PTR lRet;
3598 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3599 if (lRet)
3600 return lRet; /* else continue message processing */
3601 }
3602 switch (wMsg)
3603 {
3604 case WM_INITDIALOG:
3605 return FD31_WMInitDialog(hWnd, wParam, lParam);
3606
3607 case WM_MEASUREITEM:
3608 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3609
3610 case WM_DRAWITEM:
3611 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3612
3613 case WM_COMMAND:
3614 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3615 #if 0
3616 case WM_CTLCOLOR:
3617 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3618 switch (HIWORD(lParam))
3619 {
3620 case CTLCOLOR_BTN:
3621 SetTextColor((HDC16)wParam, 0x00000000);
3622 return hGRAYBrush;
3623 case CTLCOLOR_STATIC:
3624 SetTextColor((HDC16)wParam, 0x00000000);
3625 return hGRAYBrush;
3626 }
3627 break;
3628 #endif
3629 }
3630 return FALSE;
3631 }
3632
3633
3634 /***********************************************************************
3635 * GetFileName31A [internal]
3636 *
3637 * Creates a win31 style dialog box for the user to select a file to open/save.
3638 */
3639 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3640 UINT dlgType /* type dialogue : open/save */
3641 )
3642 {
3643 HINSTANCE hInst;
3644 BOOL bRet = FALSE;
3645 PFD31_DATA lfs;
3646 FD31_CALLBACKS callbacks;
3647
3648 if (!lpofn || !FD31_Init()) return FALSE;
3649
3650 TRACE("ofn flags %08lx\n", lpofn->Flags);
3651 FD32_SetupCallbacks(&callbacks);
3652 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3653 if (lfs)
3654 {
3655 hInst = (HINSTANCE)GetWindowLongPtrA( lpofn->hwndOwner, GWLP_HINSTANCE );
3656 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3657 FD32_FileOpenDlgProc, (LPARAM)lfs);
3658 FD31_DestroyPrivate(lfs);
3659 }
3660
3661 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3662 return bRet;
3663 }
3664
3665 /***********************************************************************
3666 * GetFileName31W [internal]
3667 *
3668 * Creates a win31 style dialog box for the user to select a file to open/save
3669 */
3670 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3671 UINT dlgType /* type dialogue : open/save */
3672 )
3673 {
3674 HINSTANCE hInst;
3675 BOOL bRet = FALSE;
3676 PFD31_DATA lfs;
3677 FD31_CALLBACKS callbacks;
3678
3679 if (!lpofn || !FD31_Init()) return FALSE;
3680
3681 FD32_SetupCallbacks(&callbacks);
3682 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3683 if (lfs)
3684 {
3685 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3686 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3687 FD32_FileOpenDlgProc, (LPARAM)lfs);
3688 FD31_DestroyPrivate(lfs);
3689 }
3690
3691 TRACE("file %s, file offset %d, ext offset %d\n",
3692 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3693 return bRet;
3694 }
3695
3696 /* ------------------ APIs ---------------------- */
3697
3698 /***********************************************************************
3699 * GetOpenFileNameA (COMDLG32.@)
3700 *
3701 * Creates a dialog box for the user to select a file to open.
3702 *
3703 * RETURNS
3704 * TRUE on success: user enters a valid file
3705 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3706 *
3707 */
3708 BOOL WINAPI GetOpenFileNameA(
3709 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3710 {
3711 BOOL win16look = FALSE;
3712
3713 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3714 if (ofn->Flags & OFN_FILEMUSTEXIST)
3715 ofn->Flags |= OFN_PATHMUSTEXIST;
3716
3717 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3718 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3719
3720 if (win16look)
3721 return GetFileName31A(ofn, OPEN_DIALOG);