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