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