Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/comdlg32/filedlg.c
4389 views
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 <ctype.h>
49
#include <stdlib.h>
50
#include <stdarg.h>
51
#include <stdio.h>
52
#include <string.h>
53
54
#define COBJMACROS
55
#include "windef.h"
56
#include "winbase.h"
57
#include "winternl.h"
58
#include "winnls.h"
59
#include "wingdi.h"
60
#include "winreg.h"
61
#include "winuser.h"
62
#include "commdlg.h"
63
#include "dlgs.h"
64
#include "cdlg.h"
65
#include "cderr.h"
66
#include "shellapi.h"
67
#include "shlobj.h"
68
#include "filedlgbrowser.h"
69
#include "shlwapi.h"
70
71
#include "wine/debug.h"
72
#include "wine/heap.h"
73
74
WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
75
76
#define UNIMPLEMENTED_FLAGS \
77
(OFN_DONTADDTORECENT |\
78
OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
79
OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
80
81
/***********************************************************************
82
* Data structure and global variables
83
*/
84
typedef struct SFolder
85
{
86
int m_iImageIndex; /* Index of picture in image list */
87
HIMAGELIST hImgList;
88
int m_iIndent; /* Indentation index */
89
LPITEMIDLIST pidlItem; /* absolute pidl of the item */
90
91
} SFOLDER,*LPSFOLDER;
92
93
typedef struct tagLookInInfo
94
{
95
int iMaxIndentation;
96
UINT uSelectedItem;
97
} LookInInfos;
98
99
100
/***********************************************************************
101
* Defines and global variables
102
*/
103
104
/* Draw item constant */
105
#define XTEXTOFFSET 3
106
107
/* AddItem flags*/
108
#define LISTEND -1
109
110
/* SearchItem methods */
111
#define SEARCH_PIDL 1
112
#define SEARCH_EXP 2
113
#define ITEM_NOTFOUND -1
114
115
/* Undefined windows message sent by CreateViewObject*/
116
#define WM_GETISHELLBROWSER WM_USER+7
117
118
#define TBPLACES_CMDID_PLACE0 0xa064
119
#define TBPLACES_CMDID_PLACE1 0xa065
120
#define TBPLACES_CMDID_PLACE2 0xa066
121
#define TBPLACES_CMDID_PLACE3 0xa067
122
#define TBPLACES_CMDID_PLACE4 0xa068
123
124
/* NOTE
125
* Those macros exist in windowsx.h. However, you can't really use them since
126
* they rely on the UNICODE defines and can't be used inside Wine itself.
127
*/
128
129
/* Combo box macros */
130
#define CBGetItemDataPtr(hwnd,iItemId) \
131
SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
132
133
static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
134
static SIZE MemDialogSize = { 0, 0}; /* keep size of the (resizable) dialog */
135
136
FileOpenDlgInfos *get_filedlg_infoptr(HWND hwnd)
137
{
138
return GetPropW(hwnd, L"FileOpenDlgInfos");
139
}
140
141
static BOOL is_dialog_hooked(const FileOpenDlgInfos *info)
142
{
143
return (info->ofnInfos->Flags & OFN_ENABLEHOOK) && info->ofnInfos->lpfnHook;
144
}
145
146
static BOOL filedialog_is_readonly_hidden(const FileOpenDlgInfos *info)
147
{
148
return (info->ofnInfos->Flags & OFN_HIDEREADONLY) || (info->DlgInfos.dwDlgProp & FODPROP_SAVEDLG);
149
}
150
151
/***********************************************************************
152
* Prototypes
153
*/
154
155
/* Internal functions used by the dialog */
156
static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
157
static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
158
static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam);
159
static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
160
static BOOL FILEDLG95_OnOpen(HWND hwnd);
161
static LRESULT FILEDLG95_InitControls(HWND hwnd);
162
static void FILEDLG95_Clean(HWND hwnd);
163
164
/* Functions used by the shell navigation */
165
static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
166
static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
167
static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
168
static void FILEDLG95_SHELL_Clean(HWND hwnd);
169
170
/* Functions used by the EDIT box */
171
static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
172
173
/* Functions used by the filetype combo box */
174
static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
175
static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
176
static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
177
static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
178
179
/* Functions used by the Look In combo box */
180
static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
181
static LRESULT FILEDLG95_LOOKIN_DrawItem(HWND hwnd, LPDRAWITEMSTRUCT pDIStruct);
182
static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
183
static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
184
static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
185
static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
186
static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
187
int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
188
static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
189
190
/* Functions for dealing with the most-recently-used registry keys */
191
static void FILEDLG95_MRU_load_filename(LPWSTR stored_path);
192
static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret);
193
static void FILEDLG95_MRU_save_filename(LPCWSTR filename);
194
195
/* Miscellaneous tool functions */
196
static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
197
IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
198
LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
199
static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
200
static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
201
static UINT GetNumSelected( IDataObject *doSelected );
202
static void COMCTL32_ReleaseStgMedium(STGMEDIUM medium);
203
204
static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
205
static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
206
static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
207
static BOOL BrowseSelectedFolder(HWND hwnd);
208
209
static BOOL get_config_key_as_dword(HKEY hkey, const WCHAR *name, DWORD *value)
210
{
211
DWORD type, data, size;
212
213
size = sizeof(data);
214
if (hkey && !RegQueryValueExW(hkey, name, 0, &type, (BYTE *)&data, &size))
215
{
216
*value = data;
217
return TRUE;
218
}
219
220
return FALSE;
221
}
222
223
static BOOL get_config_key_dword(HKEY hkey, const WCHAR *name, DWORD *value)
224
{
225
DWORD type, data, size;
226
227
size = sizeof(data);
228
if (hkey && !RegQueryValueExW(hkey, name, 0, &type, (BYTE *)&data, &size) && type == REG_DWORD)
229
{
230
*value = data;
231
return TRUE;
232
}
233
234
return FALSE;
235
}
236
237
static BOOL get_config_key_string(HKEY hkey, const WCHAR *name, WCHAR **value)
238
{
239
DWORD type, size;
240
WCHAR *str;
241
242
if (RegQueryValueExW(hkey, name, 0, &type, NULL, &size))
243
return FALSE;
244
if (type != REG_SZ && type != REG_EXPAND_SZ)
245
return FALSE;
246
247
str = heap_alloc(size);
248
if (RegQueryValueExW(hkey, name, 0, &type, (BYTE *)str, &size))
249
{
250
heap_free(str);
251
return FALSE;
252
}
253
254
*value = str;
255
return TRUE;
256
}
257
258
static BOOL is_places_bar_enabled(const FileOpenDlgInfos *fodInfos)
259
{
260
DWORD value;
261
HKEY hkey;
262
263
if (fodInfos->ofnInfos->lStructSize != sizeof(*fodInfos->ofnInfos) ||
264
(fodInfos->ofnInfos->FlagsEx & OFN_EX_NOPLACESBAR) ||
265
!(fodInfos->ofnInfos->Flags & OFN_EXPLORER))
266
{
267
return FALSE;
268
}
269
270
if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Comdlg32", &hkey))
271
return TRUE;
272
273
value = 0;
274
get_config_key_as_dword(hkey, L"NoPlacesBar", &value);
275
RegCloseKey(hkey);
276
return value == 0;
277
}
278
279
static void filedlg_collect_places_pidls(FileOpenDlgInfos *fodInfos)
280
{
281
static const int default_places[] =
282
{
283
CSIDL_DESKTOP,
284
CSIDL_MYDOCUMENTS,
285
CSIDL_DRIVES,
286
};
287
unsigned int i;
288
HKEY hkey;
289
290
if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Comdlg32\\Placesbar",
291
&hkey))
292
{
293
for (i = 0; i < ARRAY_SIZE(fodInfos->places); i++)
294
{
295
WCHAR nameW[8];
296
DWORD value;
297
HRESULT hr;
298
WCHAR *str;
299
300
swprintf(nameW, ARRAY_SIZE(nameW), L"Place%d", i);
301
if (get_config_key_dword(hkey, nameW, &value))
302
{
303
hr = SHGetSpecialFolderLocation(NULL, value, &fodInfos->places[i]);
304
if (FAILED(hr))
305
WARN("Unrecognized special folder %lu.\n", value);
306
}
307
else if (get_config_key_string(hkey, nameW, &str))
308
{
309
hr = SHParseDisplayName(str, NULL, &fodInfos->places[i], 0, NULL);
310
if (FAILED(hr))
311
WARN("Failed to parse custom places location, %s.\n", debugstr_w(str));
312
heap_free(str);
313
}
314
}
315
316
/* FIXME: eliminate duplicates. */
317
318
RegCloseKey(hkey);
319
return;
320
}
321
322
for (i = 0; i < ARRAY_SIZE(default_places); i++)
323
SHGetSpecialFolderLocation(NULL, default_places[i], &fodInfos->places[i]);
324
}
325
326
/***********************************************************************
327
* GetFileName95
328
*
329
* Creates an Open common dialog box that lets the user select
330
* the drive, directory, and the name of a file or set of files to open.
331
*
332
* IN : The FileOpenDlgInfos structure associated with the dialog
333
* OUT : TRUE on success
334
* FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
335
*/
336
static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
337
{
338
LRESULT lRes;
339
void *template;
340
HRSRC hRes;
341
HANDLE hDlgTmpl = 0;
342
WORD templateid;
343
344
/* test for missing functionality */
345
if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
346
{
347
FIXME("Flags 0x%08lx not yet implemented\n",
348
fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
349
}
350
351
/* Create the dialog from a template */
352
353
if (is_places_bar_enabled(fodInfos))
354
templateid = NEWFILEOPENV2ORD;
355
else
356
templateid = NEWFILEOPENORD;
357
358
if (!(hRes = FindResourceW(COMDLG32_hInstance, MAKEINTRESOURCEW(templateid), (LPCWSTR)RT_DIALOG)))
359
{
360
COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
361
return FALSE;
362
}
363
if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
364
!(template = LockResource( hDlgTmpl )))
365
{
366
COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
367
return FALSE;
368
}
369
370
/* msdn: explorer style dialogs permit sizing by default.
371
* The OFN_ENABLESIZING flag is only needed when a hook or
372
* custom template is provided */
373
if( (fodInfos->ofnInfos->Flags & OFN_EXPLORER) &&
374
!(fodInfos->ofnInfos->Flags & ( OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
375
fodInfos->ofnInfos->Flags |= OFN_ENABLESIZING;
376
377
if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
378
{
379
fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
380
fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
381
}
382
383
/* old style hook messages */
384
if (is_dialog_hooked(fodInfos))
385
{
386
fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
387
fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
388
fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
389
fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
390
}
391
392
if (fodInfos->unicode)
393
lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
394
template,
395
fodInfos->ofnInfos->hwndOwner,
396
FileOpenDlgProc95,
397
(LPARAM) fodInfos);
398
else
399
lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
400
template,
401
fodInfos->ofnInfos->hwndOwner,
402
FileOpenDlgProc95,
403
(LPARAM) fodInfos);
404
if (fodInfos->ole_initialized)
405
OleUninitialize();
406
407
/* Unable to create the dialog */
408
if( lRes == -1)
409
return FALSE;
410
411
return lRes;
412
}
413
414
static WCHAR *heap_strdupAtoW(const char *str)
415
{
416
WCHAR *ret;
417
INT len;
418
419
if (!str)
420
return NULL;
421
422
len = MultiByteToWideChar(CP_ACP, 0, str, -1, 0, 0);
423
ret = heap_alloc(len * sizeof(WCHAR));
424
MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
425
426
return ret;
427
}
428
429
static void init_filedlg_infoW(OPENFILENAMEW *ofn, FileOpenDlgInfos *info)
430
{
431
INITCOMMONCONTROLSEX icc;
432
433
/* Initialize ComboBoxEx32 */
434
icc.dwSize = sizeof(icc);
435
icc.dwICC = ICC_USEREX_CLASSES;
436
InitCommonControlsEx(&icc);
437
438
/* Initialize CommDlgExtendedError() */
439
COMDLG32_SetCommDlgExtendedError(0);
440
441
memset(info, 0, sizeof(*info));
442
443
/* Pass in the original ofn */
444
info->ofnInfos = ofn;
445
446
info->title = ofn->lpstrTitle;
447
info->defext = ofn->lpstrDefExt;
448
info->filter = ofn->lpstrFilter;
449
info->customfilter = ofn->lpstrCustomFilter;
450
451
if (ofn->lpstrFile)
452
{
453
info->filename = heap_alloc(ofn->nMaxFile * sizeof(WCHAR));
454
lstrcpynW(info->filename, ofn->lpstrFile, ofn->nMaxFile);
455
}
456
457
if (ofn->lpstrInitialDir)
458
{
459
DWORD len = ExpandEnvironmentStringsW(ofn->lpstrInitialDir, NULL, 0);
460
if (len)
461
{
462
info->initdir = heap_alloc(len * sizeof(WCHAR));
463
ExpandEnvironmentStringsW(ofn->lpstrInitialDir, info->initdir, len);
464
}
465
}
466
467
info->unicode = TRUE;
468
}
469
470
static void init_filedlg_infoA(OPENFILENAMEA *ofn, FileOpenDlgInfos *info)
471
{
472
OPENFILENAMEW ofnW;
473
int len;
474
475
ofnW = *(OPENFILENAMEW *)ofn;
476
477
ofnW.lpstrInitialDir = heap_strdupAtoW(ofn->lpstrInitialDir);
478
ofnW.lpstrDefExt = heap_strdupAtoW(ofn->lpstrDefExt);
479
ofnW.lpstrTitle = heap_strdupAtoW(ofn->lpstrTitle);
480
481
if (ofn->lpstrFile)
482
{
483
len = MultiByteToWideChar(CP_ACP, 0, ofn->lpstrFile, ofn->nMaxFile, NULL, 0);
484
ofnW.lpstrFile = heap_alloc(len * sizeof(WCHAR));
485
MultiByteToWideChar(CP_ACP, 0, ofn->lpstrFile, ofn->nMaxFile, ofnW.lpstrFile, len);
486
ofnW.nMaxFile = len;
487
}
488
489
if (ofn->lpstrFilter)
490
{
491
LPCSTR s;
492
int n;
493
494
/* filter is a list... title\0ext\0......\0\0 */
495
s = ofn->lpstrFilter;
496
while (*s) s = s+strlen(s)+1;
497
s++;
498
n = s - ofn->lpstrFilter;
499
len = MultiByteToWideChar(CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0);
500
ofnW.lpstrFilter = heap_alloc(len * sizeof(WCHAR));
501
MultiByteToWideChar(CP_ACP, 0, ofn->lpstrFilter, n, (WCHAR *)ofnW.lpstrFilter, len);
502
}
503
504
/* convert lpstrCustomFilter */
505
if (ofn->lpstrCustomFilter)
506
{
507
int n, len;
508
LPCSTR s;
509
510
/* customfilter contains a pair of strings... title\0ext\0 */
511
s = ofn->lpstrCustomFilter;
512
if (*s) s = s+strlen(s)+1;
513
if (*s) s = s+strlen(s)+1;
514
n = s - ofn->lpstrCustomFilter;
515
len = MultiByteToWideChar(CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0);
516
ofnW.lpstrCustomFilter = heap_alloc(len * sizeof(WCHAR));
517
MultiByteToWideChar(CP_ACP, 0, ofn->lpstrCustomFilter, n, ofnW.lpstrCustomFilter, len);
518
}
519
520
init_filedlg_infoW(&ofnW, info);
521
522
/* fixup A-specific fields */
523
info->ofnInfos = (OPENFILENAMEW *)ofn;
524
info->unicode = FALSE;
525
526
/* free what was duplicated */
527
heap_free((void *)ofnW.lpstrInitialDir);
528
heap_free(ofnW.lpstrFile);
529
}
530
531
/***********************************************************************
532
* GetFileDialog95
533
*
534
* Call GetFileName95 with this structure and clean the memory.
535
*/
536
static BOOL GetFileDialog95(FileOpenDlgInfos *info, UINT dlg_type)
537
{
538
WCHAR *current_dir = NULL;
539
unsigned int i;
540
BOOL ret;
541
542
/* save current directory */
543
if (info->ofnInfos->Flags & OFN_NOCHANGEDIR)
544
{
545
current_dir = heap_alloc(MAX_PATH * sizeof(WCHAR));
546
GetCurrentDirectoryW(MAX_PATH, current_dir);
547
}
548
549
switch (dlg_type)
550
{
551
case OPEN_DIALOG:
552
ret = GetFileName95(info);
553
break;
554
case SAVE_DIALOG:
555
info->DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
556
ret = GetFileName95(info);
557
break;
558
default:
559
ret = FALSE;
560
}
561
562
if (current_dir)
563
{
564
SetCurrentDirectoryW(current_dir);
565
heap_free(current_dir);
566
}
567
568
if (!info->unicode)
569
{
570
heap_free((void *)info->defext);
571
heap_free((void *)info->title);
572
heap_free((void *)info->filter);
573
heap_free((void *)info->customfilter);
574
}
575
576
heap_free(info->filename);
577
heap_free(info->initdir);
578
579
for (i = 0; i < ARRAY_SIZE(info->places); i++)
580
ILFree(info->places[i]);
581
582
return ret;
583
}
584
585
/******************************************************************************
586
* COMDLG32_GetDisplayNameOf [internal]
587
*
588
* Helper function to get the display name for a pidl.
589
*/
590
static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
591
LPSHELLFOLDER psfDesktop;
592
STRRET strret;
593
594
if (FAILED(SHGetDesktopFolder(&psfDesktop)))
595
return FALSE;
596
597
if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
598
IShellFolder_Release(psfDesktop);
599
return FALSE;
600
}
601
602
IShellFolder_Release(psfDesktop);
603
return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
604
}
605
606
/******************************************************************************
607
* COMDLG32_GetCanonicalPath [internal]
608
*
609
* Helper function to get the canonical path.
610
*/
611
void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent,
612
LPWSTR lpstrFile, LPWSTR lpstrPathAndFile)
613
{
614
WCHAR lpstrTemp[MAX_PATH];
615
616
/* Get the current directory name */
617
if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent, lpstrPathAndFile))
618
{
619
/* last fallback */
620
GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
621
}
622
PathAddBackslashW(lpstrPathAndFile);
623
624
TRACE("current directory=%s, file=%s\n", debugstr_w(lpstrPathAndFile), debugstr_w(lpstrFile));
625
626
/* if the user specified a fully qualified path use it */
627
if(PathIsRelativeW(lpstrFile))
628
{
629
lstrcatW(lpstrPathAndFile, lpstrFile);
630
}
631
else
632
{
633
/* does the path have a drive letter? */
634
if (PathGetDriveNumberW(lpstrFile) == -1)
635
lstrcpyW(lpstrPathAndFile+2, lpstrFile);
636
else
637
lstrcpyW(lpstrPathAndFile, lpstrFile);
638
}
639
640
/* resolve "." and ".." */
641
PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
642
lstrcpyW(lpstrPathAndFile, lpstrTemp);
643
TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
644
}
645
646
/***********************************************************************
647
* COMDLG32_SplitFileNames [internal]
648
*
649
* Creates a delimited list of filenames.
650
*/
651
int COMDLG32_SplitFileNames(LPWSTR lpstrEdit, UINT nStrLen, LPWSTR *lpstrFileList, UINT *sizeUsed)
652
{
653
UINT nStrCharCount = 0; /* index in src buffer */
654
UINT nFileIndex = 0; /* index in dest buffer */
655
UINT nFileCount = 0; /* number of files */
656
657
/* we might get single filename without any '"',
658
* so we need nStrLen + terminating \0 + end-of-list \0 */
659
*lpstrFileList = heap_alloc((nStrLen + 2) * sizeof(WCHAR));
660
*sizeUsed = 0;
661
662
/* build delimited file list from filenames */
663
while ( nStrCharCount <= nStrLen )
664
{
665
if ( lpstrEdit[nStrCharCount]=='"' )
666
{
667
nStrCharCount++;
668
while ((nStrCharCount <= nStrLen) && (lpstrEdit[nStrCharCount]!='"'))
669
{
670
(*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
671
nStrCharCount++;
672
}
673
(*lpstrFileList)[nFileIndex++] = 0;
674
nFileCount++;
675
}
676
nStrCharCount++;
677
}
678
679
/* single, unquoted string */
680
if ((nStrLen > 0) && (nFileIndex == 0) )
681
{
682
lstrcpyW(*lpstrFileList, lpstrEdit);
683
nFileIndex = lstrlenW(lpstrEdit) + 1;
684
nFileCount = 1;
685
}
686
687
/* trailing \0 */
688
(*lpstrFileList)[nFileIndex++] = '\0';
689
690
*sizeUsed = nFileIndex;
691
return nFileCount;
692
}
693
694
/***********************************************************************
695
* ArrangeCtrlPositions [internal]
696
*
697
* NOTE: Make sure to add testcases for any changes made here.
698
*/
699
static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
700
{
701
HWND hwndChild, hwndStc32;
702
RECT rectParent, rectChild, rectStc32;
703
INT help_fixup = 0;
704
int chgx, chgy;
705
706
/* Take into account if open as read only checkbox and help button
707
* are hidden
708
*/
709
if (hide_help)
710
{
711
RECT rectHelp, rectCancel;
712
GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
713
GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
714
/* subtract the height of the help button plus the space between
715
* the help button and the cancel button to the height of the dialog
716
*/
717
help_fixup = rectHelp.bottom - rectCancel.bottom;
718
}
719
720
/*
721
There are two possibilities to add components to the default file dialog box.
722
723
By default, all the new components are added below the standard dialog box (the else case).
724
725
However, if there is a static text component with the stc32 id, a special case happens.
726
The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
727
in the window and the cx and cy indicate how to size the window.
728
Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
729
of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
730
731
*/
732
733
GetClientRect(hwndParentDlg, &rectParent);
734
735
/* when arranging controls we have to use fixed parent size */
736
rectParent.bottom -= help_fixup;
737
738
hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
739
if (hwndStc32)
740
{
741
GetWindowRect(hwndStc32, &rectStc32);
742
MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
743
744
/* set the size of the stc32 control according to the size of
745
* client area of the parent dialog
746
*/
747
SetWindowPos(hwndStc32, 0,
748
0, 0,
749
rectParent.right, rectParent.bottom,
750
SWP_NOMOVE | SWP_NOZORDER);
751
}
752
else
753
SetRectEmpty(&rectStc32);
754
755
/* this part moves controls of the child dialog */
756
hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
757
while (hwndChild)
758
{
759
if (hwndChild != hwndStc32)
760
{
761
GetWindowRect(hwndChild, &rectChild);
762
MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
763
764
/* move only if stc32 exist */
765
if (hwndStc32 && rectChild.left > rectStc32.right)
766
{
767
/* move to the right of visible controls of the parent dialog */
768
rectChild.left += rectParent.right;
769
rectChild.left -= rectStc32.right;
770
}
771
/* move even if stc32 doesn't exist */
772
if (rectChild.top >= rectStc32.bottom)
773
{
774
/* move below visible controls of the parent dialog */
775
rectChild.top += rectParent.bottom;
776
rectChild.top -= rectStc32.bottom - rectStc32.top;
777
}
778
779
SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
780
0, 0, SWP_NOSIZE | SWP_NOZORDER);
781
}
782
hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
783
}
784
785
/* this part moves controls of the parent dialog */
786
hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
787
while (hwndChild)
788
{
789
if (hwndChild != hwndChildDlg)
790
{
791
GetWindowRect(hwndChild, &rectChild);
792
MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
793
794
/* left,top of stc32 marks the position of controls
795
* from the parent dialog
796
*/
797
rectChild.left += rectStc32.left;
798
rectChild.top += rectStc32.top;
799
800
SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
801
0, 0, SWP_NOSIZE | SWP_NOZORDER);
802
}
803
hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
804
}
805
806
/* calculate the size of the resulting dialog */
807
808
/* here we have to use original parent size */
809
GetClientRect(hwndParentDlg, &rectParent);
810
GetClientRect(hwndChildDlg, &rectChild);
811
TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent),
812
wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32));
813
814
if (hwndStc32)
815
{
816
/* width */
817
if (rectParent.right > rectStc32.right - rectStc32.left)
818
chgx = rectChild.right - ( rectStc32.right - rectStc32.left);
819
else
820
chgx = rectChild.right - rectParent.right;
821
/* height */
822
if (rectParent.bottom > rectStc32.bottom - rectStc32.top)
823
chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup;
824
else
825
/* Unconditionally set new dialog
826
* height to that of the child
827
*/
828
chgy = rectChild.bottom - rectParent.bottom;
829
}
830
else
831
{
832
chgx = 0;
833
chgy = rectChild.bottom - help_fixup;
834
}
835
/* set the size of the parent dialog */
836
GetWindowRect(hwndParentDlg, &rectParent);
837
SetWindowPos(hwndParentDlg, 0,
838
0, 0,
839
rectParent.right - rectParent.left + chgx,
840
rectParent.bottom - rectParent.top + chgy,
841
SWP_NOMOVE | SWP_NOZORDER);
842
}
843
844
static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
845
{
846
switch(uMsg) {
847
case WM_INITDIALOG:
848
return TRUE;
849
}
850
return FALSE;
851
}
852
853
static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
854
{
855
LPCVOID template;
856
HRSRC hRes;
857
HANDLE hDlgTmpl = 0;
858
HWND hChildDlg = 0;
859
860
TRACE("%p, %p\n", fodInfos, hwnd);
861
862
/*
863
* If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
864
* structure's hInstance parameter is not a HINSTANCE, but
865
* instead a pointer to a template resource to use.
866
*/
867
if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
868
{
869
HINSTANCE hinst;
870
if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
871
{
872
hinst = COMDLG32_hInstance;
873
if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
874
{
875
COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
876
return NULL;
877
}
878
}
879
else
880
{
881
hinst = fodInfos->ofnInfos->hInstance;
882
if(fodInfos->unicode)
883
{
884
LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
885
hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
886
}
887
else
888
{
889
LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
890
hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
891
}
892
if (!hRes)
893
{
894
COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
895
return NULL;
896
}
897
if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
898
!(template = LockResource( hDlgTmpl )))
899
{
900
COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
901
return NULL;
902
}
903
}
904
if (fodInfos->unicode)
905
hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
906
is_dialog_hooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
907
(LPARAM)fodInfos->ofnInfos);
908
else
909
hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
910
is_dialog_hooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
911
(LPARAM)fodInfos->ofnInfos);
912
return hChildDlg;
913
}
914
else if (is_dialog_hooked(fodInfos))
915
{
916
RECT rectHwnd;
917
struct {
918
DLGTEMPLATE tmplate;
919
WORD menu,class,title;
920
} temp;
921
GetClientRect(hwnd,&rectHwnd);
922
temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
923
temp.tmplate.dwExtendedStyle = 0;
924
temp.tmplate.cdit = 0;
925
temp.tmplate.x = 0;
926
temp.tmplate.y = 0;
927
temp.tmplate.cx = 0;
928
temp.tmplate.cy = 0;
929
temp.menu = temp.class = temp.title = 0;
930
931
hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
932
hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
933
934
return hChildDlg;
935
}
936
return NULL;
937
}
938
939
/***********************************************************************
940
* SendCustomDlgNotificationMessage
941
*
942
* Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
943
*/
944
945
LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
946
{
947
FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwndParentDlg);
948
LRESULT hook_result;
949
OFNOTIFYW ofnNotify;
950
951
TRACE("%p %d\n", hwndParentDlg, uCode);
952
953
if (!fodInfos || !fodInfos->DlgInfos.hwndCustomDlg)
954
return 0;
955
956
TRACE("CALL NOTIFY for %d\n", uCode);
957
958
ofnNotify.hdr.hwndFrom = hwndParentDlg;
959
ofnNotify.hdr.idFrom = 0;
960
ofnNotify.hdr.code = uCode;
961
ofnNotify.lpOFN = fodInfos->ofnInfos;
962
ofnNotify.pszFile = NULL;
963
964
if (fodInfos->unicode)
965
hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg, WM_NOTIFY, 0, (LPARAM)&ofnNotify);
966
else
967
hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg, WM_NOTIFY, 0, (LPARAM)&ofnNotify);
968
969
TRACE("RET NOTIFY retval %#Ix\n", hook_result);
970
971
return hook_result;
972
}
973
974
static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
975
{
976
UINT len, total;
977
WCHAR *p, *buffer;
978
FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
979
980
TRACE("CDM_GETFILEPATH:\n");
981
982
if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
983
return -1;
984
985
/* get path and filenames */
986
len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
987
buffer = heap_alloc( (len + 2 + MAX_PATH) * sizeof(WCHAR) );
988
COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
989
if (len)
990
{
991
p = buffer + lstrlenW(buffer);
992
*p++ = '\\';
993
SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
994
}
995
if (fodInfos->unicode)
996
{
997
total = lstrlenW( buffer) + 1;
998
if (result) lstrcpynW( result, buffer, size );
999
TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
1000
}
1001
else
1002
{
1003
total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
1004
if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
1005
TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
1006
}
1007
heap_free( buffer );
1008
return total;
1009
}
1010
1011
/***********************************************************************
1012
* FILEDLG95_HandleCustomDialogMessages
1013
*
1014
* Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
1015
*/
1016
static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1017
{
1018
FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
1019
WCHAR lpstrPath[MAX_PATH];
1020
INT_PTR retval;
1021
1022
if(!fodInfos) return FALSE;
1023
1024
switch(uMsg)
1025
{
1026
case CDM_GETFILEPATH:
1027
retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
1028
break;
1029
1030
case CDM_GETFOLDERPATH:
1031
TRACE("CDM_GETFOLDERPATH:\n");
1032
COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
1033
if (lParam)
1034
{
1035
if (fodInfos->unicode)
1036
lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
1037
else
1038
WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
1039
(LPSTR)lParam, (int)wParam, NULL, NULL);
1040
}
1041
retval = lstrlenW(lpstrPath) + 1;
1042
break;
1043
1044
case CDM_GETFOLDERIDLIST:
1045
retval = ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
1046
if (retval <= wParam)
1047
memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
1048
break;
1049
1050
case CDM_GETSPEC:
1051
TRACE("CDM_GETSPEC:\n");
1052
retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
1053
if (lParam)
1054
{
1055
if (fodInfos->unicode)
1056
SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1057
else
1058
SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1059
}
1060
break;
1061
1062
case CDM_SETCONTROLTEXT:
1063
TRACE("CDM_SETCONTROLTEXT:\n");
1064
if ( lParam )
1065
{
1066
if( fodInfos->unicode )
1067
SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
1068
else
1069
SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
1070
}
1071
retval = TRUE;
1072
break;
1073
1074
case CDM_HIDECONTROL:
1075
/* MSDN states that it should fail for not OFN_EXPLORER case */
1076
if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1077
{
1078
HWND control = GetDlgItem( hwnd, wParam );
1079
if (control) ShowWindow( control, SW_HIDE );
1080
retval = TRUE;
1081
}
1082
else retval = FALSE;
1083
break;
1084
1085
default:
1086
if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1087
FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1088
return FALSE;
1089
}
1090
SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1091
return TRUE;
1092
}
1093
1094
/***********************************************************************
1095
* FILEDLG95_OnWMGetMMI
1096
*
1097
* WM_GETMINMAXINFO message handler for resizable dialogs
1098
*/
1099
static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
1100
{
1101
FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
1102
if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1103
if( fodInfos->initial_size.x || fodInfos->initial_size.y)
1104
{
1105
mmiptr->ptMinTrackSize = fodInfos->initial_size;
1106
}
1107
return TRUE;
1108
}
1109
1110
/***********************************************************************
1111
* FILEDLG95_OnWMSize
1112
*
1113
* WM_SIZE message handler, resize the dialog. Re-arrange controls.
1114
*
1115
* FIXME: this could be made more elaborate. Now use a simple scheme
1116
* where the file view is enlarged and the controls are either moved
1117
* vertically or horizontally to get out of the way. Only the "grip"
1118
* is moved in both directions to stay in the corner.
1119
*/
1120
static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam)
1121
{
1122
RECT rc, rcview;
1123
int chgx, chgy;
1124
HWND ctrl;
1125
HDWP hdwp;
1126
FileOpenDlgInfos *fodInfos;
1127
1128
if( wParam != SIZE_RESTORED) return FALSE;
1129
fodInfos = get_filedlg_infoptr(hwnd);
1130
if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1131
/* get the new dialog rectangle */
1132
GetWindowRect( hwnd, &rc);
1133
TRACE("%p, size from %ld,%ld to %ld,%ld\n", hwnd, fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
1134
rc.right -rc.left, rc.bottom -rc.top);
1135
/* not initialized yet */
1136
if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1137
((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1138
(fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1139
return FALSE;
1140
chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1141
chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1142
fodInfos->sizedlg.cx = rc.right - rc.left;
1143
fodInfos->sizedlg.cy = rc.bottom - rc.top;
1144
/* change the size of the view window */
1145
GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1146
MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1147
hdwp = BeginDeferWindowPos( 10);
1148
DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1149
rcview.right - rcview.left + chgx,
1150
rcview.bottom - rcview.top + chgy,
1151
SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1152
/* change position and sizes of the controls */
1153
for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1154
{
1155
int ctrlid = GetDlgCtrlID( ctrl);
1156
GetWindowRect( ctrl, &rc);
1157
MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1158
if( ctrl == fodInfos->DlgInfos.hwndGrip)
1159
{
1160
DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1161
0, 0,
1162
SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1163
}
1164
else if( rc.top > rcview.bottom)
1165
{
1166
/* if it was below the shell view
1167
* move to bottom */
1168
switch( ctrlid)
1169
{
1170
/* file name (edit or comboboxex) and file types combo change also width */
1171
case edt1:
1172
case cmb13:
1173
case cmb1:
1174
DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1175
rc.right - rc.left + chgx, rc.bottom - rc.top,
1176
SWP_NOACTIVATE | SWP_NOZORDER);
1177
break;
1178
/* then these buttons must move out of the way */
1179
case IDOK:
1180
case IDCANCEL:
1181
case pshHelp:
1182
DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1183
0, 0,
1184
SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1185
break;
1186
default:
1187
DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1188
0, 0,
1189
SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1190
}
1191
}
1192
else if( rc.left > rcview.right)
1193
{
1194
/* if it was to the right of the shell view
1195
* move to right */
1196
DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1197
0, 0,
1198
SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1199
}
1200
else
1201
/* special cases */
1202
{
1203
switch( ctrlid)
1204
{
1205
#if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1206
case IDC_LOOKIN:
1207
DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1208
rc.right - rc.left + chgx, rc.bottom - rc.top,
1209
SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1210
break;
1211
case IDC_TOOLBARSTATIC:
1212
case IDC_TOOLBAR:
1213
DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1214
0, 0,
1215
SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1216
break;
1217
#endif
1218
/* not resized in windows. Since wine uses this invisible control
1219
* to size the browser view it needs to be resized */
1220
case IDC_SHELLSTATIC:
1221
DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1222
rc.right - rc.left + chgx,
1223
rc.bottom - rc.top + chgy,
1224
SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1225
break;
1226
case IDC_TOOLBARPLACES:
1227
DeferWindowPos( hdwp, ctrl, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top + chgy,
1228
SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1229
break;
1230
}
1231
}
1232
}
1233
if(fodInfos->DlgInfos.hwndCustomDlg &&
1234
(fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1235
{
1236
for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1237
ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1238
{
1239
GetWindowRect( ctrl, &rc);
1240
MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1241
if( rc.top > rcview.bottom)
1242
{
1243
/* if it was below the shell view
1244
* move to bottom */
1245
DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1246
rc.right - rc.left, rc.bottom - rc.top,
1247
SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1248
}
1249
else if( rc.left > rcview.right)
1250
{
1251
/* if it was to the right of the shell view
1252
* move to right */
1253
DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1254
rc.right - rc.left, rc.bottom - rc.top,
1255
SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1256
}
1257
}
1258
/* size the custom dialog at the end: some applications do some
1259
* control re-arranging at this point */
1260
GetClientRect(hwnd, &rc);
1261
DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1262
0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1263
}
1264
EndDeferWindowPos( hdwp);
1265
/* should not be needed */
1266
RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1267
return TRUE;
1268
}
1269
1270
/***********************************************************************
1271
* FileOpenDlgProc95
1272
*
1273
* File open dialog procedure
1274
*/
1275
INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1276
{
1277
#if 0
1278
TRACE("%p 0x%04x\n", hwnd, uMsg);
1279
#endif
1280
1281
switch(uMsg)
1282
{
1283
case WM_INITDIALOG:
1284
{
1285
FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1286
RECT rc, rcstc;
1287
int gripx = GetSystemMetrics( SM_CYHSCROLL);
1288
int gripy = GetSystemMetrics( SM_CYVSCROLL);
1289
1290
/* Some shell namespace extensions depend on COM being initialized. */
1291
if (SUCCEEDED(OleInitialize(NULL)))
1292
fodInfos->ole_initialized = TRUE;
1293
1294
SetPropW(hwnd, L"FileOpenDlgInfos", fodInfos);
1295
1296
FILEDLG95_InitControls(hwnd);
1297
1298
if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1299
{
1300
DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
1301
DWORD ex_style = GetWindowLongW(hwnd, GWL_EXSTYLE);
1302
RECT client, client_adjusted;
1303
1304
if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1305
{
1306
style |= WS_SIZEBOX;
1307
ex_style |= WS_EX_WINDOWEDGE;
1308
}
1309
else
1310
style &= ~WS_SIZEBOX;
1311
SetWindowLongW(hwnd, GWL_STYLE, style);
1312
SetWindowLongW(hwnd, GWL_EXSTYLE, ex_style);
1313
1314
GetClientRect( hwnd, &client );
1315
GetClientRect( hwnd, &client_adjusted );
1316
AdjustWindowRectEx( &client_adjusted, style, FALSE, ex_style );
1317
1318
GetWindowRect( hwnd, &rc );
1319
rc.right += client_adjusted.right - client.right;
1320
rc.bottom += client_adjusted.bottom - client.bottom;
1321
SetWindowPos(hwnd, 0, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_FRAMECHANGED | SWP_NOACTIVATE |
1322
SWP_NOZORDER | SWP_NOMOVE);
1323
1324
GetWindowRect( hwnd, &rc );
1325
fodInfos->DlgInfos.hwndGrip =
1326
CreateWindowExA( 0, "SCROLLBAR", NULL,
1327
WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1328
SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1329
rc.right - gripx, rc.bottom - gripy,
1330
gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1331
}
1332
1333
fodInfos->DlgInfos.hwndCustomDlg =
1334
CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1335
1336
FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1337
FILEDLG95_FillControls(hwnd, wParam, lParam);
1338
1339
if( fodInfos->DlgInfos.hwndCustomDlg)
1340
ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1341
1342
if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1343
SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1344
SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1345
}
1346
1347
/* if the app has changed the position of the invisible listbox,
1348
* change that of the listview (browser) as well */
1349
GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
1350
GetWindowRect( GetDlgItem( hwnd, IDC_SHELLSTATIC ), &rcstc);
1351
if( !EqualRect( &rc, &rcstc))
1352
{
1353
MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
1354
SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
1355
rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
1356
SWP_NOACTIVATE | SWP_NOZORDER);
1357
}
1358
1359
if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1360
{
1361
GetWindowRect( hwnd, &rc);
1362
fodInfos->sizedlg.cx = rc.right - rc.left;
1363
fodInfos->sizedlg.cy = rc.bottom - rc.top;
1364
fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1365
fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1366
GetClientRect( hwnd, &rc);
1367
SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1368
rc.right - gripx, rc.bottom - gripy,
1369
0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1370
/* resize the dialog to the previous invocation */
1371
if( MemDialogSize.cx && MemDialogSize.cy)
1372
SetWindowPos( hwnd, NULL,
1373
0, 0, MemDialogSize.cx, MemDialogSize.cy,
1374
SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1375
}
1376
1377
if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1378
SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1379
1380
return 0;
1381
}
1382
case WM_SIZE:
1383
return FILEDLG95_OnWMSize(hwnd, wParam);
1384
case WM_GETMINMAXINFO:
1385
return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1386
case WM_COMMAND:
1387
return FILEDLG95_OnWMCommand(hwnd, wParam);
1388
case WM_DRAWITEM:
1389
{
1390
switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1391
{
1392
case IDC_LOOKIN:
1393
FILEDLG95_LOOKIN_DrawItem(hwnd, (LPDRAWITEMSTRUCT)lParam);
1394
return TRUE;
1395
}
1396
}
1397
return FALSE;
1398
1399
case WM_GETISHELLBROWSER:
1400
return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1401
1402
case WM_DESTROY:
1403
{
1404
FileOpenDlgInfos * fodInfos = get_filedlg_infoptr(hwnd);
1405
HWND places_bar = GetDlgItem(hwnd, IDC_TOOLBARPLACES);
1406
HIMAGELIST himl;
1407
1408
if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1409
MemDialogSize = fodInfos->sizedlg;
1410
1411
if (places_bar)
1412
{
1413
himl = (HIMAGELIST)SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_GETIMAGELIST, 0, 0);
1414
SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_SETIMAGELIST, 0, 0);
1415
ImageList_Destroy(himl);
1416
}
1417
return FALSE;
1418
}
1419
1420
case WM_NCDESTROY:
1421
RemovePropW(hwnd, L"FileOpenDlgInfos");
1422
return 0;
1423
1424
case WM_NOTIFY:
1425
{
1426
LPNMHDR lpnmh = (LPNMHDR)lParam;
1427
UINT stringId = -1;
1428
1429
/* set up the button tooltips strings */
1430
if(TTN_GETDISPINFOA == lpnmh->code )
1431
{
1432
LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1433
switch(lpnmh->idFrom )
1434
{
1435
/* Up folder button */
1436
case FCIDM_TB_UPFOLDER:
1437
stringId = IDS_UPFOLDER;
1438
break;
1439
/* New folder button */
1440
case FCIDM_TB_NEWFOLDER:
1441
stringId = IDS_NEWFOLDER;
1442
break;
1443
/* List option button */
1444
case FCIDM_TB_SMALLICON:
1445
stringId = IDS_LISTVIEW;
1446
break;
1447
/* Details option button */
1448
case FCIDM_TB_REPORTVIEW:
1449
stringId = IDS_REPORTVIEW;
1450
break;
1451
/* Desktop button */
1452
case FCIDM_TB_DESKTOP:
1453
stringId = IDS_TODESKTOP;
1454
break;
1455
default:
1456
stringId = 0;
1457
}
1458
lpdi->hinst = COMDLG32_hInstance;
1459
lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1460
}
1461
return FALSE;
1462
}
1463
default :
1464
if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1465
return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1466
return FALSE;
1467
}
1468
}
1469
1470
static inline BOOL filename_is_edit( const FileOpenDlgInfos *info )
1471
{
1472
return (info->ofnInfos->lStructSize == OPENFILENAME_SIZE_VERSION_400W) &&
1473
(info->ofnInfos->Flags & (OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE));
1474
}
1475
1476
/***********************************************************************
1477
* FILEDLG95_InitControls
1478
*
1479
* WM_INITDIALOG message handler (before hook notification)
1480
*/
1481
static LRESULT FILEDLG95_InitControls(HWND hwnd)
1482
{
1483
BOOL win2000plus = FALSE;
1484
BOOL win98plus = FALSE;
1485
BOOL handledPath = FALSE;
1486
OSVERSIONINFOW osVi;
1487
1488
static const TBBUTTON tbb[] =
1489
{
1490
{0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1491
{VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1492
{0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1493
{VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1494
{0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1495
{VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1496
{0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1497
{VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1498
{VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1499
};
1500
static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR};
1501
1502
RECT rectTB;
1503
RECT rectlook;
1504
1505
HIMAGELIST toolbarImageList;
1506
ITEMIDLIST *desktopPidl;
1507
SHFILEINFOW fileinfo;
1508
1509
FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
1510
1511
TRACE("%p\n", fodInfos);
1512
1513
/* Get windows version emulating */
1514
osVi.dwOSVersionInfoSize = sizeof(osVi);
1515
GetVersionExW(&osVi);
1516
if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1517
win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1518
} else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1519
win2000plus = (osVi.dwMajorVersion > 4);
1520
if (win2000plus) win98plus = TRUE;
1521
}
1522
TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1523
1524
1525
/* Use either the edit or the comboboxex for the filename control */
1526
if (filename_is_edit( fodInfos ))
1527
{
1528
DestroyWindow( GetDlgItem( hwnd, cmb13 ) );
1529
fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, edt1 );
1530
}
1531
else
1532
{
1533
DestroyWindow( GetDlgItem( hwnd, edt1 ) );
1534
fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, cmb13 );
1535
}
1536
1537
/* Get the hwnd of the controls */
1538
fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1539
fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1540
1541
GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1542
MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1543
1544
/* construct the toolbar */
1545
GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1546
MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1547
1548
rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1549
rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1550
rectTB.left = rectlook.right;
1551
rectTB.top = rectlook.top-1;
1552
1553
if (fodInfos->unicode)
1554
fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1555
WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT | CCS_NODIVIDER | CCS_NORESIZE,
1556
rectTB.left, rectTB.top,
1557
rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1558
hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1559
else
1560
fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1561
WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT | CCS_NODIVIDER | CCS_NORESIZE,
1562
rectTB.left, rectTB.top,
1563
rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1564
hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1565
1566
SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1567
1568
/* FIXME: use TB_LOADIMAGES when implemented */
1569
/* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1570
SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1571
SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba);
1572
1573
/* Retrieve and add desktop icon to the toolbar */
1574
toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L);
1575
SHGetSpecialFolderLocation(hwnd, CSIDL_DESKTOP, &desktopPidl);
1576
SHGetFileInfoW((const WCHAR *)desktopPidl, 0, &fileinfo, sizeof(fileinfo),
1577
SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON);
1578
ImageList_AddIcon(toolbarImageList, fileinfo.hIcon);
1579
1580
DestroyIcon(fileinfo.hIcon);
1581
CoTaskMemFree(desktopPidl);
1582
1583
/* Finish Toolbar Construction */
1584
SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1585
SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1586
1587
if (is_places_bar_enabled(fodInfos))
1588
{
1589
TBBUTTON tb = { 0 };
1590
HIMAGELIST himl;
1591
RECT rect;
1592
int i, cx;
1593
1594
SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_BUTTONSTRUCTSIZE, 0, 0);
1595
GetClientRect(GetDlgItem(hwnd, IDC_TOOLBARPLACES), &rect);
1596
cx = rect.right - rect.left;
1597
1598
SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_SETBUTTONWIDTH, 0, MAKELPARAM(cx, cx));
1599
himl = ImageList_Create(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), ILC_COLOR32, 4, 1);
1600
1601
filedlg_collect_places_pidls(fodInfos);
1602
for (i = 0; i < ARRAY_SIZE(fodInfos->places); i++)
1603
{
1604
int index;
1605
1606
if (!fodInfos->places[i])
1607
continue;
1608
1609
memset(&fileinfo, 0, sizeof(fileinfo));
1610
SHGetFileInfoW((const WCHAR *)fodInfos->places[i], 0, &fileinfo, sizeof(fileinfo),
1611
SHGFI_PIDL | SHGFI_DISPLAYNAME | SHGFI_ICON);
1612
index = ImageList_AddIcon(himl, fileinfo.hIcon);
1613
1614
tb.iBitmap = index;
1615
tb.iString = (INT_PTR)fileinfo.szDisplayName;
1616
tb.fsState = TBSTATE_ENABLED | TBSTATE_WRAP;
1617
tb.idCommand = TBPLACES_CMDID_PLACE0 + i;
1618
SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_ADDBUTTONSW, 1, (LPARAM)&tb);
1619
1620
DestroyIcon(fileinfo.hIcon);
1621
}
1622
1623
SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_SETIMAGELIST, 0, (LPARAM)himl);
1624
SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_SETBUTTONSIZE, 0, MAKELPARAM(cx, cx * 3 / 4));
1625
}
1626
1627
/* Set the window text with the text specified in the OPENFILENAME structure */
1628
if(fodInfos->title)
1629
{
1630
SetWindowTextW(hwnd,fodInfos->title);
1631
}
1632
else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1633
{
1634
WCHAR buf[64];
1635
LoadStringW(COMDLG32_hInstance, IDS_SAVE_AS, buf, ARRAY_SIZE(buf));
1636
SetWindowTextW(hwnd, buf);
1637
}
1638
1639
/* Initialise the file name edit control */
1640
handledPath = FALSE;
1641
TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1642
1643
if(fodInfos->filename)
1644
{
1645
/* 1. If win2000 or higher and filename contains a path, use it
1646
in preference over the lpstrInitialDir */
1647
if (win2000plus && *fodInfos->filename && wcspbrk(fodInfos->filename, L"\\")) {
1648
WCHAR tmpBuf[MAX_PATH];
1649
WCHAR *nameBit;
1650
DWORD result;
1651
1652
result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1653
if (result) {
1654
1655
/* nameBit is always shorter than the original filename. It may be NULL
1656
* when the filename contains only a drive name instead of file name */
1657
if (nameBit)
1658
{
1659
lstrcpyW(fodInfos->filename,nameBit);
1660
*nameBit = 0x00;
1661
}
1662
else
1663
*fodInfos->filename = '\0';
1664
1665
heap_free(fodInfos->initdir);
1666
fodInfos->initdir = heap_alloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1667
lstrcpyW(fodInfos->initdir, tmpBuf);
1668
handledPath = TRUE;
1669
TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1670
debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1671
}
1672
SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1673
1674
} else {
1675
SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1676
}
1677
}
1678
1679
/* 2. (All platforms) If initdir is not null, then use it */
1680
if (!handledPath && fodInfos->initdir && *fodInfos->initdir)
1681
{
1682
/* Work out the proper path as supplied one might be relative */
1683
/* (Here because supplying '.' as dir browses to My Computer) */
1684
WCHAR tmpBuf[MAX_PATH];
1685
WCHAR tmpBuf2[MAX_PATH];
1686
WCHAR *nameBit;
1687
DWORD result;
1688
1689
lstrcpyW(tmpBuf, fodInfos->initdir);
1690
if (PathFileExistsW(tmpBuf)) {
1691
/* initdir does not have to be a directory. If a file is
1692
* specified, the dir part is taken */
1693
if (PathIsDirectoryW(tmpBuf)) {
1694
PathAddBackslashW(tmpBuf);
1695
lstrcatW(tmpBuf, L"*");
1696
}
1697
result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1698
if (result) {
1699
*nameBit = 0x00;
1700
heap_free(fodInfos->initdir);
1701
fodInfos->initdir = heap_alloc((lstrlenW(tmpBuf2) + 1) * sizeof(WCHAR));
1702
lstrcpyW(fodInfos->initdir, tmpBuf2);
1703
handledPath = TRUE;
1704
TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1705
}
1706
}
1707
else if (fodInfos->initdir)
1708
{
1709
heap_free(fodInfos->initdir);
1710
fodInfos->initdir = NULL;
1711
TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1712
}
1713
}
1714
1715
if (!handledPath && (!fodInfos->initdir || !*fodInfos->initdir))
1716
{
1717
/* 3. All except w2k+: if filename contains a path use it */
1718
if (!win2000plus && fodInfos->filename && *fodInfos->filename &&
1719
wcspbrk(fodInfos->filename, L"\\")) {
1720
WCHAR tmpBuf[MAX_PATH];
1721
WCHAR *nameBit;
1722
DWORD result;
1723
1724
result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1725
tmpBuf, &nameBit);
1726
if (result) {
1727
int len;
1728
1729
/* nameBit is always shorter than the original filename */
1730
lstrcpyW(fodInfos->filename, nameBit);
1731
*nameBit = 0x00;
1732
1733
len = lstrlenW(tmpBuf);
1734
heap_free(fodInfos->initdir);
1735
fodInfos->initdir = heap_alloc((len+1)*sizeof(WCHAR));
1736
lstrcpyW(fodInfos->initdir, tmpBuf);
1737
1738
handledPath = TRUE;
1739
TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1740
debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1741
}
1742
SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1743
}
1744
1745
/* 4. Win2000+: Recently used */
1746
if (!handledPath && win2000plus) {
1747
fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1748
fodInfos->initdir[0] = '\0';
1749
1750
FILEDLG95_MRU_load_filename(fodInfos->initdir);
1751
1752
if (fodInfos->initdir[0] && PathFileExistsW(fodInfos->initdir)){
1753
handledPath = TRUE;
1754
}else{
1755
heap_free(fodInfos->initdir);
1756
fodInfos->initdir = NULL;
1757
}
1758
}
1759
1760
/* 5. win98+ and win2000+ if any files of specified filter types in
1761
current directory, use it */
1762
if (win98plus && !handledPath && fodInfos->filter && *fodInfos->filter) {
1763
1764
LPCWSTR lpstrPos = fodInfos->filter;
1765
WIN32_FIND_DATAW FindFileData;
1766
HANDLE hFind;
1767
1768
while (1)
1769
{
1770
/* filter is a list... title\0ext\0......\0\0 */
1771
1772
/* Skip the title */
1773
if(! *lpstrPos) break; /* end */
1774
lpstrPos += lstrlenW(lpstrPos) + 1;
1775
1776
/* See if any files exist in the current dir with this extension */
1777
if(! *lpstrPos) break; /* end */
1778
1779
hFind = FindFirstFileW(lpstrPos, &FindFileData);
1780
1781
if (hFind == INVALID_HANDLE_VALUE) {
1782
/* None found - continue search */
1783
lpstrPos += lstrlenW(lpstrPos) + 1;
1784
1785
} else {
1786
1787
heap_free(fodInfos->initdir);
1788
fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1789
GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1790
1791
handledPath = TRUE;
1792
TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1793
debugstr_w(lpstrPos));
1794
FindClose(hFind);
1795
break;
1796
}
1797
}
1798
}
1799
1800
/* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1801
if (!handledPath && (win2000plus || win98plus)) {
1802
fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1803
1804
if (SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir) == S_OK)
1805
{
1806
if (SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir) == S_OK)
1807
{
1808
/* last fallback */
1809
GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1810
TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1811
}
1812
else
1813
TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1814
}
1815
else
1816
TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1817
1818
handledPath = TRUE;
1819
} else if (!handledPath) {
1820
fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1821
GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1822
handledPath = TRUE;
1823
TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1824
}
1825
}
1826
SetFocus( fodInfos->DlgInfos.hwndFileName );
1827
TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1828
1829
/* Must the open as read only check box be checked ?*/
1830
if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1831
{
1832
SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1833
}
1834
1835
/* Must the open as read only check box be hidden? */
1836
if (filedialog_is_readonly_hidden(fodInfos))
1837
{
1838
ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1839
EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1840
}
1841
1842
/* Must the help button be hidden? */
1843
if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1844
{
1845
ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1846
EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1847
}
1848
1849
/* change Open to Save */
1850
if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1851
{
1852
WCHAR buf[16];
1853
LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, ARRAY_SIZE(buf));
1854
SetDlgItemTextW(hwnd, IDOK, buf);
1855
LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, ARRAY_SIZE(buf));
1856
SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1857
}
1858
1859
/* Initialize the filter combo box */
1860
FILEDLG95_FILETYPE_Init(hwnd);
1861
1862
return 0;
1863
}
1864
1865
/***********************************************************************
1866
* FILEDLG95_ResizeControls
1867
*
1868
* WM_INITDIALOG message handler (after hook notification)
1869
*/
1870
static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1871
{
1872
FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1873
1874
if (fodInfos->DlgInfos.hwndCustomDlg)
1875
{
1876
RECT rc;
1877
UINT flags = SWP_NOACTIVATE;
1878
1879
ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1880
filedialog_is_readonly_hidden(fodInfos) && !(fodInfos->ofnInfos->Flags & OFN_SHOWHELP));
1881
1882
/* resize the custom dialog to the parent size */
1883
if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1884
GetClientRect(hwnd, &rc);
1885
else
1886
{
1887
/* our own fake template is zero sized and doesn't have children, so
1888
* there is no need to resize it. Picasa depends on it.
1889
*/
1890
flags |= SWP_NOSIZE;
1891
SetRectEmpty(&rc);
1892
}
1893
SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1894
0, 0, rc.right, rc.bottom, flags);
1895
}
1896
else
1897
{
1898
/* Resize the height; if opened as read-only, checkbox and help button are
1899
* hidden and we are not using a custom template nor a customDialog
1900
*/
1901
if (filedialog_is_readonly_hidden(fodInfos) &&
1902
(!(fodInfos->ofnInfos->Flags &
1903
(OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1904
{
1905
RECT rectDlg, rectHelp, rectCancel;
1906
GetWindowRect(hwnd, &rectDlg);
1907
GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1908
GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1909
/* subtract the height of the help button plus the space between the help
1910
* button and the cancel button to the height of the dialog
1911
*/
1912
SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1913
(rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1914
SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1915
}
1916
}
1917
return TRUE;
1918
}
1919
1920
/***********************************************************************
1921
* FILEDLG95_FillControls
1922
*
1923
* WM_INITDIALOG message handler (after hook notification)
1924
*/
1925
static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1926
{
1927
LPITEMIDLIST pidlItemId = NULL;
1928
1929
FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1930
1931
TRACE("dir=%s file=%s\n",
1932
debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1933
1934
/* Get the initial directory pidl */
1935
1936
if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1937
{
1938
WCHAR path[MAX_PATH];
1939
1940
GetCurrentDirectoryW(MAX_PATH,path);
1941
pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1942
}
1943
1944
/* Initialise shell objects */
1945
FILEDLG95_SHELL_Init(hwnd);
1946
1947
/* Initialize the Look In combo box */
1948
FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1949
1950
/* Browse to the initial directory */
1951
IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1952
1953
ILFree(pidlItemId);
1954
1955
return TRUE;
1956
}
1957
/***********************************************************************
1958
* FILEDLG95_Clean
1959
*
1960
* Regroups all the cleaning functions of the filedlg
1961
*/
1962
void FILEDLG95_Clean(HWND hwnd)
1963
{
1964
FILEDLG95_FILETYPE_Clean(hwnd);
1965
FILEDLG95_LOOKIN_Clean(hwnd);
1966
FILEDLG95_SHELL_Clean(hwnd);
1967
}
1968
1969
1970
/***********************************************************************
1971
* Browse to arbitrary pidl
1972
*/
1973
static void filedlg_browse_to_pidl(const FileOpenDlgInfos *info, LPITEMIDLIST pidl)
1974
{
1975
TRACE("%p, %p\n", info->ShellInfos.hwndOwner, pidl);
1976
1977
IShellBrowser_BrowseObject(info->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
1978
if (info->ofnInfos->Flags & OFN_EXPLORER)
1979
SendCustomDlgNotificationMessage(info->ShellInfos.hwndOwner, CDN_FOLDERCHANGE);
1980
}
1981
1982
/***********************************************************************
1983
* FILEDLG95_OnWMCommand
1984
*
1985
* WM_COMMAND message handler
1986
*/
1987
static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam)
1988
{
1989
FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
1990
WORD wNotifyCode = HIWORD(wParam); /* notification code */
1991
WORD id = LOWORD(wParam); /* item, control, or accelerator identifier */
1992
1993
switch (id)
1994
{
1995
/* OK button */
1996
case IDOK:
1997
FILEDLG95_OnOpen(hwnd);
1998
break;
1999
/* Cancel button */
2000
case IDCANCEL:
2001
FILEDLG95_Clean(hwnd);
2002
EndDialog(hwnd, FALSE);
2003
break;
2004
/* Filetype combo box */
2005
case IDC_FILETYPE:
2006
FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
2007
break;
2008
/* LookIn combo box */
2009
case IDC_LOOKIN:
2010
FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
2011
break;
2012
2013
/* --- toolbar --- */
2014
/* Up folder button */
2015
case FCIDM_TB_UPFOLDER:
2016
FILEDLG95_SHELL_UpFolder(hwnd);
2017
break;
2018
/* New folder button */
2019
case FCIDM_TB_NEWFOLDER:
2020
FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
2021
break;
2022
/* List option button */
2023
case FCIDM_TB_SMALLICON:
2024
FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
2025
break;
2026
/* Details option button */
2027
case FCIDM_TB_REPORTVIEW:
2028
FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
2029
break;
2030
2031
case FCIDM_TB_DESKTOP:
2032
{
2033
LPITEMIDLIST pidl;
2034
2035
SHGetSpecialFolderLocation(0, CSIDL_DESKTOP, &pidl);
2036
filedlg_browse_to_pidl(fodInfos, pidl);
2037
ILFree(pidl);
2038
break;
2039
}
2040
2041
/* Places bar */
2042
case TBPLACES_CMDID_PLACE0:
2043
case TBPLACES_CMDID_PLACE1:
2044
case TBPLACES_CMDID_PLACE2:
2045
case TBPLACES_CMDID_PLACE3:
2046
case TBPLACES_CMDID_PLACE4:
2047
filedlg_browse_to_pidl(fodInfos, fodInfos->places[id - TBPLACES_CMDID_PLACE0]);
2048
break;
2049
2050
case edt1:
2051
case cmb13:
2052
break;
2053
2054
}
2055
/* Do not use the listview selection anymore */
2056
fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
2057
return 0;
2058
}
2059
2060
/***********************************************************************
2061
* FILEDLG95_OnWMGetIShellBrowser
2062
*
2063
* WM_GETISHELLBROWSER message handler
2064
*/
2065
static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
2066
{
2067
FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2068
2069
TRACE("\n");
2070
2071
SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
2072
2073
return TRUE;
2074
}
2075
2076
2077
/***********************************************************************
2078
* FILEDLG95_SendFileOK
2079
*
2080
* Sends the CDN_FILEOK notification if required
2081
*
2082
* RETURNS
2083
* TRUE if the dialog should close
2084
* FALSE if the dialog should not be closed
2085
*/
2086
static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
2087
{
2088
/* ask the hook if we can close */
2089
if (is_dialog_hooked(fodInfos))
2090
{
2091
LRESULT retval = 0;
2092
2093
TRACE("---\n");
2094
/* First send CDN_FILEOK as MSDN doc says */
2095
if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2096
retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
2097
if( retval)
2098
{
2099
TRACE("canceled\n");
2100
return FALSE;
2101
}
2102
2103
/* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
2104
retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
2105
fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
2106
if( retval)
2107
{
2108
TRACE("canceled\n");
2109
return FALSE;
2110
}
2111
}
2112
return TRUE;
2113
}
2114
2115
/***********************************************************************
2116
* FILEDLG95_OnOpenMultipleFiles
2117
*
2118
* Handles the opening of multiple files.
2119
*
2120
* FIXME
2121
* check destination buffer size
2122
*/
2123
BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
2124
{
2125
FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2126
WCHAR lpstrPathSpec[MAX_PATH] = {0};
2127
UINT nCount, nSizePath;
2128
2129
TRACE("\n");
2130
2131
if(fodInfos->unicode)
2132
{
2133
LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2134
ofn->lpstrFile[0] = '\0';
2135
}
2136
else
2137
{
2138
LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
2139
ofn->lpstrFile[0] = '\0';
2140
}
2141
2142
COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
2143
2144
if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2145
( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2146
! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2147
{
2148
LPWSTR lpstrTemp = lpstrFileList;
2149
2150
for ( nCount = 0; nCount < nFileCount; nCount++ )
2151
{
2152
LPITEMIDLIST pidl;
2153
2154
pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
2155
if (!pidl)
2156
{
2157
WCHAR lpstrNotFound[100];
2158
WCHAR lpstrMsg[100];
2159
WCHAR tmp[400];
2160
2161
LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
2162
LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
2163
2164
lstrcpyW(tmp, lpstrTemp);
2165
lstrcatW(tmp, L"\n");
2166
lstrcatW(tmp, lpstrNotFound);
2167
lstrcatW(tmp, L"\n");
2168
lstrcatW(tmp, lpstrMsg);
2169
2170
MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
2171
return FALSE;
2172
}
2173
2174
/* move to the next file in the list of files */
2175
lpstrTemp += lstrlenW(lpstrTemp) + 1;
2176
ILFree(pidl);
2177
}
2178
}
2179
2180
nSizePath = lstrlenW(lpstrPathSpec) + 1;
2181
if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
2182
{
2183
/* For "oldstyle" dialog the components have to
2184
be separated by blanks (not '\0'!) and short
2185
filenames have to be used! */
2186
FIXME("Components have to be separated by blanks\n");
2187
}
2188
if(fodInfos->unicode)
2189
{
2190
LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2191
lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
2192
memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
2193
}
2194
else
2195
{
2196
LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2197
2198
if (ofn->lpstrFile != NULL)
2199
{
2200
nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
2201
ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2202
if (ofn->nMaxFile > nSizePath)
2203
{
2204
WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
2205
ofn->lpstrFile + nSizePath,
2206
ofn->nMaxFile - nSizePath, NULL, NULL);
2207
}
2208
}
2209
}
2210
2211
fodInfos->ofnInfos->nFileOffset = nSizePath;
2212
fodInfos->ofnInfos->nFileExtension = 0;
2213
2214
if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2215
return FALSE;
2216
2217
/* clean and exit */
2218
FILEDLG95_Clean(hwnd);
2219
return EndDialog(hwnd,TRUE);
2220
}
2221
2222
/* Returns the 'slot name' of the given module_name in the registry's
2223
* most-recently-used list. This will be an ASCII value in the
2224
* range ['a','z'). Returns zero on error.
2225
*
2226
* The slot's value in the registry has the form:
2227
* module_name\0mru_path\0
2228
*
2229
* If stored_path is given, then stored_path will contain the path name
2230
* stored in the registry's MRU list for the given module_name.
2231
*
2232
* If hkey_ret is given, then hkey_ret will be a handle to the registry's
2233
* MRU list key for the given module_name.
2234
*/
2235
static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret)
2236
{
2237
WCHAR mru_list[32], *cur_mru_slot;
2238
BOOL taken[25] = {0};
2239
DWORD mru_list_size = sizeof(mru_list), key_type = -1, i;
2240
HKEY hkey_tmp, *hkey;
2241
LONG ret;
2242
2243
if(hkey_ret)
2244
hkey = hkey_ret;
2245
else
2246
hkey = &hkey_tmp;
2247
2248
if(stored_path)
2249
*stored_path = '\0';
2250
2251
ret = RegCreateKeyW(HKEY_CURRENT_USER,
2252
L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisitedMRU", hkey);
2253
if(ret){
2254
WARN("Unable to create MRU key: %ld\n", ret);
2255
return 0;
2256
}
2257
2258
ret = RegGetValueW(*hkey, NULL, L"MRUList", RRF_RT_REG_SZ, &key_type,
2259
(LPBYTE)mru_list, &mru_list_size);
2260
if(ret || key_type != REG_SZ){
2261
if(ret == ERROR_FILE_NOT_FOUND)
2262
return 'a';
2263
2264
WARN("Error getting MRUList data: type: %ld, ret: %ld\n", key_type, ret);
2265
RegCloseKey(*hkey);
2266
return 0;
2267
}
2268
2269
for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot){
2270
WCHAR value_data[MAX_PATH], value_name[2] = {0};
2271
DWORD value_data_size = sizeof(value_data);
2272
2273
*value_name = *cur_mru_slot;
2274
2275
ret = RegGetValueW(*hkey, NULL, value_name, RRF_RT_REG_BINARY,
2276
&key_type, (LPBYTE)value_data, &value_data_size);
2277
if(ret || key_type != REG_BINARY){
2278
WARN("Error getting MRU slot data: type: %ld, ret: %ld\n", key_type, ret);
2279
continue;
2280
}
2281
2282
if(!wcsicmp(module_name, value_data)){
2283
if(!hkey_ret)
2284
RegCloseKey(*hkey);
2285
if(stored_path)
2286
lstrcpyW(stored_path, value_data + lstrlenW(value_data) + 1);
2287
return *value_name;
2288
}
2289
}
2290
2291
if(!hkey_ret)
2292
RegCloseKey(*hkey);
2293
2294
/* the module name isn't in the registry, so find the next open slot */
2295
for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot)
2296
taken[*cur_mru_slot - 'a'] = TRUE;
2297
for(i = 0; i < 25; ++i){
2298
if(!taken[i])
2299
return i + 'a';
2300
}
2301
2302
/* all slots are taken, so return the last one in MRUList */
2303
--cur_mru_slot;
2304
return *cur_mru_slot;
2305
}
2306
2307
/* save the given filename as most-recently-used path for this module */
2308
static void FILEDLG95_MRU_save_filename(LPCWSTR filename)
2309
{
2310
WCHAR module_path[MAX_PATH], *module_name, slot, slot_name[2] = {0};
2311
LONG ret;
2312
HKEY hkey;
2313
2314
/* get the current executable's name */
2315
if (!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, ARRAY_SIZE(module_path)))
2316
{
2317
WARN("GotModuleFileName failed: %ld\n", GetLastError());
2318
return;
2319
}
2320
module_name = wcsrchr(module_path, '\\');
2321
if(!module_name)
2322
module_name = module_path;
2323
else
2324
module_name += 1;
2325
2326
slot = FILEDLG95_MRU_get_slot(module_name, NULL, &hkey);
2327
if(!slot)
2328
return;
2329
*slot_name = slot;
2330
2331
{ /* update the slot's info */
2332
WCHAR *path_ends, *final;
2333
DWORD path_len, final_len;
2334
2335
/* use only the path segment of `filename' */
2336
path_ends = wcsrchr(filename, '\\');
2337
path_len = path_ends - filename;
2338
2339
final_len = path_len + lstrlenW(module_name) + 2;
2340
2341
final = heap_alloc(final_len * sizeof(WCHAR));
2342
if(!final)
2343
return;
2344
lstrcpyW(final, module_name);
2345
memcpy(final + lstrlenW(final) + 1, filename, path_len * sizeof(WCHAR));
2346
final[final_len-1] = '\0';
2347
2348
ret = RegSetValueExW(hkey, slot_name, 0, REG_BINARY, (LPBYTE)final,
2349
final_len * sizeof(WCHAR));
2350
if(ret){
2351
WARN("Error saving MRU data to slot %s: %ld\n", wine_dbgstr_w(slot_name), ret);
2352
heap_free(final);
2353
RegCloseKey(hkey);
2354
return;
2355
}
2356
2357
heap_free(final);
2358
}
2359
2360
{ /* update MRUList value */
2361
WCHAR old_mru_list[32], new_mru_list[32];
2362
WCHAR *old_mru_slot, *new_mru_slot = new_mru_list;
2363
DWORD mru_list_size = sizeof(old_mru_list), key_type;
2364
2365
ret = RegGetValueW(hkey, NULL, L"MRUList", RRF_RT_ANY, &key_type,
2366
(LPBYTE)old_mru_list, &mru_list_size);
2367
if(ret || key_type != REG_SZ){
2368
if(ret == ERROR_FILE_NOT_FOUND){
2369
new_mru_list[0] = slot;
2370
new_mru_list[1] = '\0';
2371
}else{
2372
WARN("Error getting MRUList data: type: %ld, ret: %ld\n", key_type, ret);
2373
RegCloseKey(hkey);
2374
return;
2375
}
2376
}else{
2377
/* copy old list data over so that the new slot is at the start
2378
* of the list */
2379
*new_mru_slot++ = slot;
2380
for(old_mru_slot = old_mru_list; *old_mru_slot; ++old_mru_slot){
2381
if(*old_mru_slot != slot)
2382
*new_mru_slot++ = *old_mru_slot;
2383
}
2384
*new_mru_slot = '\0';
2385
}
2386
2387
ret = RegSetValueExW(hkey, L"MRUList", 0, REG_SZ, (LPBYTE)new_mru_list,
2388
(lstrlenW(new_mru_list) + 1) * sizeof(WCHAR));
2389
if(ret){
2390
WARN("Error saving MRUList data: %ld\n", ret);
2391
RegCloseKey(hkey);
2392
return;
2393
}
2394
}
2395
}
2396
2397
/* load the most-recently-used path for this module */
2398
static void FILEDLG95_MRU_load_filename(LPWSTR stored_path)
2399
{
2400
WCHAR module_path[MAX_PATH], *module_name;
2401
2402
/* get the current executable's name */
2403
if (!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, ARRAY_SIZE(module_path)))
2404
{
2405
WARN("GotModuleFileName failed: %ld\n", GetLastError());
2406
return;
2407
}
2408
module_name = wcsrchr(module_path, '\\');
2409
if(!module_name)
2410
module_name = module_path;
2411
else
2412
module_name += 1;
2413
2414
FILEDLG95_MRU_get_slot(module_name, stored_path, NULL);
2415
TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path));
2416
}
2417
2418
void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
2419
{
2420
WCHAR strMsgTitle[MAX_PATH];
2421
WCHAR strMsgText [MAX_PATH];
2422
if (idCaption)
2423
LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, ARRAY_SIZE(strMsgTitle));
2424
else
2425
strMsgTitle[0] = '\0';
2426
LoadStringW(COMDLG32_hInstance, idText, strMsgText, ARRAY_SIZE(strMsgText));
2427
MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
2428
}
2429
2430
int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile, IShellFolder **ppsf,
2431
HWND hwnd, DWORD flags, BOOL isSaveDlg, int defAction)
2432
{
2433
int nOpenAction = defAction;
2434
LPWSTR lpszTemp, lpszTemp1;
2435
LPITEMIDLIST pidl = NULL;
2436
2437
/* check for invalid chars */
2438
if((wcspbrk(lpstrPathAndFile+3, L"/:<>|") != NULL) && !(flags & OFN_NOVALIDATE))
2439
{
2440
FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2441
return FALSE;
2442
}
2443
2444
if (FAILED (SHGetDesktopFolder(ppsf))) return FALSE;
2445
2446
lpszTemp1 = lpszTemp = lpstrPathAndFile;
2447
while (lpszTemp1)
2448
{
2449
LPSHELLFOLDER lpsfChild;
2450
WCHAR lpwstrTemp[MAX_PATH];
2451
DWORD dwEaten, dwAttributes;
2452
LPWSTR p;
2453
2454
lstrcpyW(lpwstrTemp, lpszTemp);
2455
if (lpszTemp == lpstrPathAndFile && (p = PathSkipRootW(lpwstrTemp)))
2456
{
2457
*p = 0;
2458
}
2459
else
2460
{
2461
p = PathFindNextComponentW(lpwstrTemp);
2462
if (!p) break; /* end of path */
2463
*p = 0;
2464
}
2465
lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2466
2467
/* There are no wildcards when OFN_NOVALIDATE is set */
2468
if(*lpszTemp==0 && !(flags & OFN_NOVALIDATE))
2469
{
2470
/* if the last element is a wildcard do a search */
2471
if(wcspbrk(lpszTemp1, L"*?") != NULL)
2472
{
2473
nOpenAction = ONOPEN_SEARCH;
2474
break;
2475
}
2476
}
2477
lpszTemp1 = lpszTemp;
2478
2479
TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), *ppsf);
2480
2481
/* append a backslash to drive letters */
2482
if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2483
((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2484
(lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2485
{
2486
PathAddBackslashW(lpwstrTemp);
2487
}
2488
2489
dwAttributes = SFGAO_FOLDER;
2490
if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2491
{
2492
/* the path component is valid, we have a pidl of the next path component */
2493
TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
2494
if(dwAttributes & SFGAO_FOLDER)
2495
{
2496
if(FAILED(IShellFolder_BindToObject(*ppsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2497
{
2498
ERR("bind to failed\n"); /* should not fail */
2499
break;
2500
}
2501
IShellFolder_Release(*ppsf);
2502
*ppsf = lpsfChild;
2503
lpsfChild = NULL;
2504
}
2505
else
2506
{
2507
TRACE("value\n");
2508
2509
/* end dialog, return value */
2510
nOpenAction = ONOPEN_OPEN;
2511
break;
2512
}
2513
ILFree(pidl);
2514
pidl = NULL;
2515
}
2516
else if (!(flags & OFN_NOVALIDATE))
2517
{
2518
if(*lpszTemp || /* points to trailing null for last path element */
2519
(lpwstrTemp[lstrlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2520
{
2521
if(flags & OFN_PATHMUSTEXIST)
2522
{
2523
FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2524
break;
2525
}
2526
}
2527
else
2528
{
2529
if( (flags & OFN_FILEMUSTEXIST) && !isSaveDlg )
2530
{
2531
FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2532
break;
2533
}
2534
}
2535
/* change to the current folder */
2536
nOpenAction = ONOPEN_OPEN;
2537
break;
2538
}
2539
else
2540
{
2541
nOpenAction = ONOPEN_OPEN;
2542
break;
2543
}
2544
}
2545
ILFree(pidl);
2546
2547
return nOpenAction;
2548
}
2549
2550
/***********************************************************************
2551
* FILEDLG95_OnOpen
2552
*
2553
* Ok button WM_COMMAND message handler
2554
*
2555
* If the function succeeds, the return value is nonzero.
2556
*/
2557
BOOL FILEDLG95_OnOpen(HWND hwnd)
2558
{
2559
FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2560
LPWSTR lpstrFileList;
2561
UINT nFileCount = 0;
2562
UINT sizeUsed = 0;
2563
BOOL ret = TRUE;
2564
WCHAR lpstrPathAndFile[MAX_PATH];
2565
LPSHELLFOLDER lpsf = NULL;
2566
int nOpenAction;
2567
2568
TRACE("hwnd=%p\n", hwnd);
2569
2570
/* try to browse the selected item */
2571
if(BrowseSelectedFolder(hwnd))
2572
return FALSE;
2573
2574
/* get the files from the edit control */
2575
nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
2576
2577
if(nFileCount == 0)
2578
return FALSE;
2579
2580
if(nFileCount > 1)
2581
{
2582
ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2583
goto ret;
2584
}
2585
2586
TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2587
2588
/*
2589
Step 1: Build a complete path name from the current folder and
2590
the filename or path in the edit box.
2591
Special cases:
2592
- the path in the edit box is a root path
2593
(with or without drive letter)
2594
- the edit box contains ".." (or a path with ".." in it)
2595
*/
2596
2597
COMDLG32_GetCanonicalPath(fodInfos->ShellInfos.pidlAbsCurrent, lpstrFileList, lpstrPathAndFile);
2598
heap_free(lpstrFileList);
2599
2600
/*
2601
Step 2: here we have a cleaned up path
2602
2603
We have to parse the path step by step to see if we have to browse
2604
to a folder if the path points to a directory or the last
2605
valid element is a directory.
2606
2607
valid variables:
2608
lpstrPathAndFile: cleaned up path
2609
*/
2610
2611
if (nFileCount &&
2612
(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2613
!(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2614
nOpenAction = ONOPEN_OPEN;
2615
else
2616
nOpenAction = ONOPEN_BROWSE;
2617
2618
nOpenAction = FILEDLG95_ValidatePathAction(lpstrPathAndFile, &lpsf, hwnd,
2619
fodInfos->ofnInfos->Flags,
2620
fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG,
2621
nOpenAction);
2622
if(!nOpenAction)
2623
goto ret;
2624
2625
/*
2626
Step 3: here we have a cleaned up and validated path
2627
2628
valid variables:
2629
lpsf: ShellFolder bound to the rightmost valid path component
2630
lpstrPathAndFile: cleaned up path
2631
nOpenAction: action to do
2632
*/
2633
TRACE("end validate sf=%p\n", lpsf);
2634
2635
switch(nOpenAction)
2636
{
2637
case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2638
TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2639
{
2640
int iPos;
2641
LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2642
DWORD len;
2643
2644
/* replace the current filter */
2645
heap_free(fodInfos->ShellInfos.lpstrCurrentFilter);
2646
len = lstrlenW(lpszTemp)+1;
2647
fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc(len * sizeof(WCHAR));
2648
lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2649
2650
/* set the filter cb to the extension when possible */
2651
if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2652
SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETCURSEL, iPos, 0);
2653
}
2654
/* fall through */
2655
case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2656
TRACE("ONOPEN_BROWSE\n");
2657
{
2658
IPersistFolder2 * ppf2;
2659
if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2660
{
2661
LPITEMIDLIST pidlCurrent;
2662
IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2663
IPersistFolder2_Release(ppf2);
2664
if (!ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2665
{
2666
if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2667
&& fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2668
{
2669
SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2670
SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_SETTEXT, 0, (LPARAM)"");
2671
}
2672
}
2673
else if( nOpenAction == ONOPEN_SEARCH )
2674
{
2675
if (fodInfos->Shell.FOIShellView)
2676
IShellView_Refresh(fodInfos->Shell.FOIShellView);
2677
}
2678
ILFree(pidlCurrent);
2679
if (filename_is_edit( fodInfos ))
2680
SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2681
else
2682
{
2683
HWND hwnd;
2684
2685
hwnd = (HWND)SendMessageA(fodInfos->DlgInfos.hwndFileName, CBEM_GETEDITCONTROL, 0, 0);
2686
SendMessageW(hwnd, EM_SETSEL, 0, -1);
2687
}
2688
}
2689
}
2690
ret = FALSE;
2691
break;
2692
case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2693
TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2694
{
2695
WCHAR *ext = NULL;
2696
2697
/* update READONLY check box flag */
2698
if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2699
fodInfos->ofnInfos->Flags |= OFN_READONLY;
2700
else
2701
fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2702
2703
/* Attach the file extension with file name*/
2704
ext = PathFindExtensionW(lpstrPathAndFile);
2705
if (! *ext && fodInfos->defext)
2706
{
2707
/* if no extension is specified with file name, then */
2708
/* attach the extension from file filter or default one */
2709
2710
WCHAR *filterExt = NULL;
2711
LPWSTR lpstrFilter = NULL;
2712
int PathLength = lstrlenW(lpstrPathAndFile);
2713
2714
/*Get the file extension from file type filter*/
2715
lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2716
fodInfos->ofnInfos->nFilterIndex-1);
2717
2718
if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2719
{
2720
WCHAR* filterSearchIndex;
2721
filterExt = heap_alloc((lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR));
2722
lstrcpyW(filterExt, lpstrFilter);
2723
2724
/* if a semicolon-separated list of file extensions was given, do not include the
2725
semicolon or anything after it in the extension.
2726
example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2727
filterSearchIndex = wcschr(filterExt, ';');
2728
if (filterSearchIndex)
2729
{
2730
filterSearchIndex[0] = '\0';
2731
}
2732
2733
/* find the file extension by searching for the first dot in filterExt */
2734
/* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2735
/* if the extension is invalid or contains a glob, ignore it */
2736
filterSearchIndex = wcschr(filterExt, '.');
2737
if (filterSearchIndex++ && !wcschr(filterSearchIndex, '*') && !wcschr(filterSearchIndex, '?'))
2738
{
2739
lstrcpyW(filterExt, filterSearchIndex);
2740
}
2741
else
2742
{
2743
heap_free(filterExt);
2744
filterExt = NULL;
2745
}
2746
}
2747
2748
if (!filterExt)
2749
{
2750
/* use the default file extension */
2751
filterExt = heap_alloc((lstrlenW(fodInfos->defext) + 1) * sizeof(WCHAR));
2752
lstrcpyW(filterExt, fodInfos->defext);
2753
}
2754
2755
if (*filterExt) /* ignore filterExt="" */
2756
{
2757
/* Attach the dot*/
2758
lstrcatW(lpstrPathAndFile, L".");
2759
/* Attach the extension */
2760
lstrcatW(lpstrPathAndFile, filterExt);
2761
}
2762
2763
heap_free(filterExt);
2764
2765
/* In Open dialog: if file does not exist try without extension */
2766
if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2767
lpstrPathAndFile[PathLength] = '\0';
2768
2769
/* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2770
if (*ext)
2771
ext++;
2772
if (!lstrcmpiW(fodInfos->defext, ext))
2773
fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2774
else
2775
fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2776
}
2777
2778
/* In Save dialog: check if the file already exists */
2779
if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2780
&& fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2781
&& PathFileExistsW(lpstrPathAndFile))
2782
{
2783
WCHAR lpstrOverwrite[100];
2784
int answer;
2785
2786
LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2787
answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2788
MB_YESNO | MB_ICONEXCLAMATION);
2789
if (answer == IDNO || answer == IDCANCEL)
2790
{
2791
ret = FALSE;
2792
goto ret;
2793
}
2794
}
2795
2796
/* In Open dialog: check if it should be created if it doesn't exist */
2797
if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2798
&& fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2799
&& !PathFileExistsW(lpstrPathAndFile))
2800
{
2801
WCHAR lpstrCreate[100];
2802
int answer;
2803
2804
LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2805
answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2806
MB_YESNO | MB_ICONEXCLAMATION);
2807
if (answer == IDNO || answer == IDCANCEL)
2808
{
2809
ret = FALSE;
2810
goto ret;
2811
}
2812
}
2813
2814
/* Check that the size of the file does not exceed buffer size.
2815
(Allow for extra \0 if OFN_MULTISELECT is set.) */
2816
if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2817
((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2818
{
2819
2820
/* fill destination buffer */
2821
if (fodInfos->ofnInfos->lpstrFile)
2822
{
2823
if(fodInfos->unicode)
2824
{
2825
LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2826
2827
lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2828
if (ofn->Flags & OFN_ALLOWMULTISELECT)
2829
ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2830
}
2831
else
2832
{
2833
LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2834
2835
WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2836
ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2837
if (ofn->Flags & OFN_ALLOWMULTISELECT)
2838
ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2839
}
2840
}
2841
2842
if(fodInfos->unicode)
2843
{
2844
LPWSTR lpszTemp;
2845
2846
/* set filename offset */
2847
lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2848
fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2849
2850
/* set extension offset */
2851
lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2852
fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2853
}
2854
else
2855
{
2856
LPSTR lpszTemp;
2857
CHAR tempFileA[MAX_PATH];
2858
2859
/* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2860
WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2861
tempFileA, sizeof(tempFileA), NULL, NULL);
2862
2863
/* set filename offset */
2864
lpszTemp = PathFindFileNameA(tempFileA);
2865
fodInfos->ofnInfos->nFileOffset = (lpszTemp - tempFileA);
2866
2867
/* set extension offset */
2868
lpszTemp = PathFindExtensionA(tempFileA);
2869
fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - tempFileA) + 1 : 0;
2870
}
2871
2872
/* set the lpstrFileTitle */
2873
if(fodInfos->ofnInfos->lpstrFileTitle)
2874
{
2875
LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2876
if(fodInfos->unicode)
2877
{
2878
LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2879
lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2880
}
2881
else
2882
{
2883
LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2884
WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2885
ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2886
}
2887
}
2888
2889
/* copy currently selected filter to lpstrCustomFilter */
2890
if (fodInfos->ofnInfos->lpstrCustomFilter)
2891
{
2892
LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2893
int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2894
NULL, 0, NULL, NULL);
2895
if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2896
{
2897
LPSTR s = ofn->lpstrCustomFilter;
2898
s += strlen(ofn->lpstrCustomFilter)+1;
2899
WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2900
s, len, NULL, NULL);
2901
}
2902
}
2903
2904
2905
if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2906
goto ret;
2907
2908
FILEDLG95_MRU_save_filename(lpstrPathAndFile);
2909
2910
TRACE("close\n");
2911
FILEDLG95_Clean(hwnd);
2912
ret = EndDialog(hwnd, TRUE);
2913
}
2914
else
2915
{
2916
WORD size;
2917
2918
size = lstrlenW(lpstrPathAndFile) + 1;
2919
if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2920
size += 1;
2921
/* return needed size in first two bytes of lpstrFile */
2922
if(fodInfos->ofnInfos->lpstrFile)
2923
*(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2924
FILEDLG95_Clean(hwnd);
2925
ret = EndDialog(hwnd, FALSE);
2926
COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2927
}
2928
}
2929
break;
2930
}
2931
2932
ret:
2933
if(lpsf) IShellFolder_Release(lpsf);
2934
return ret;
2935
}
2936
2937
/***********************************************************************
2938
* FILEDLG95_SHELL_Init
2939
*
2940
* Initialisation of the shell objects
2941
*/
2942
static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2943
{
2944
FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2945
2946
TRACE("%p\n", hwnd);
2947
2948
/*
2949
* Initialisation of the FileOpenDialogInfos structure
2950
*/
2951
2952
/* Shell */
2953
2954
/*ShellInfos */
2955
fodInfos->ShellInfos.hwndOwner = hwnd;
2956
2957
/* Disable multi-select if flag not set */
2958
if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2959
{
2960
fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2961
}
2962
fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2963
fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2964
2965
/* Construct the IShellBrowser interface */
2966
fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2967
2968
return NOERROR;
2969
}
2970
2971
/***********************************************************************
2972
* FILEDLG95_SHELL_ExecuteCommand
2973
*
2974
* Change the folder option and refresh the view
2975
* If the function succeeds, the return value is nonzero.
2976
*/
2977
static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2978
{
2979
FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2980
IContextMenu * pcm;
2981
2982
TRACE("(%p,%p)\n", hwnd, lpVerb);
2983
2984
if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2985
SVGIO_BACKGROUND,
2986
&IID_IContextMenu,
2987
(LPVOID*)&pcm)))
2988
{
2989
CMINVOKECOMMANDINFO ci;
2990
ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2991
ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2992
ci.lpVerb = lpVerb;
2993
ci.hwnd = hwnd;
2994
2995
IContextMenu_InvokeCommand(pcm, &ci);
2996
IContextMenu_Release(pcm);
2997
}
2998
2999
return FALSE;
3000
}
3001
3002
/***********************************************************************
3003
* FILEDLG95_SHELL_UpFolder
3004
*
3005
* Browse to the specified object
3006
* If the function succeeds, the return value is nonzero.
3007
*/
3008
static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
3009
{
3010
FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3011
3012
TRACE("\n");
3013
3014
if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3015
NULL,
3016
SBSP_PARENT)))
3017
{
3018
if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3019
SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3020
return TRUE;
3021
}
3022
return FALSE;
3023
}
3024
/***********************************************************************
3025
* FILEDLG95_SHELL_Clean
3026
*
3027
* Cleans the memory used by shell objects
3028
*/
3029
static void FILEDLG95_SHELL_Clean(HWND hwnd)
3030
{
3031
FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3032
3033
TRACE("\n");
3034
3035
ILFree(fodInfos->ShellInfos.pidlAbsCurrent);
3036
3037
/* clean Shell interfaces */
3038
if (fodInfos->Shell.FOIShellView)
3039
{
3040
IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
3041
IShellView_Release(fodInfos->Shell.FOIShellView);
3042
}
3043
if (fodInfos->Shell.FOIShellFolder)
3044
IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
3045
IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
3046
if (fodInfos->Shell.FOIDataObject)
3047
IDataObject_Release(fodInfos->Shell.FOIDataObject);
3048
}
3049
3050
/***********************************************************************
3051
* FILEDLG95_FILETYPE_Init
3052
*
3053
* Initialisation of the file type combo box
3054
*/
3055
static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
3056
{
3057
FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3058
int nFilters = 0; /* number of filters */
3059
int nFilterIndexCB;
3060
3061
TRACE("%p\n", hwnd);
3062
3063
if(fodInfos->customfilter)
3064
{
3065
/* customfilter has one entry... title\0ext\0
3066
* Set first entry of combo box item with customfilter
3067
*/
3068
LPWSTR lpstrExt;
3069
LPCWSTR lpstrPos = fodInfos->customfilter;
3070
3071
/* Get the title */
3072
lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
3073
3074
/* Copy the extensions */
3075
if (! *lpstrPos) return E_FAIL; /* malformed filter */
3076
if (!(lpstrExt = heap_alloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
3077
lstrcpyW(lpstrExt,lpstrPos);
3078
3079
/* Add the item at the end of the combo */
3080
SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_ADDSTRING, 0, (LPARAM)fodInfos->customfilter);
3081
SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETITEMDATA, nFilters, (LPARAM)lpstrExt);
3082
3083
nFilters++;
3084
}
3085
if(fodInfos->filter)
3086
{
3087
LPCWSTR lpstrPos = fodInfos->filter;
3088
3089
for(;;)
3090
{
3091
/* filter is a list... title\0ext\0......\0\0
3092
* Set the combo item text to the title and the item data
3093
* to the ext
3094
*/
3095
LPCWSTR lpstrDisplay;
3096
LPWSTR lpstrExt;
3097
3098
/* Get the title */
3099
if(! *lpstrPos) break; /* end */
3100
lpstrDisplay = lpstrPos;
3101
lpstrPos += lstrlenW(lpstrPos) + 1;
3102
3103
SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_ADDSTRING, 0, (LPARAM)lpstrDisplay);
3104
3105
nFilters++;
3106
3107
/* Copy the extensions */
3108
if (!(lpstrExt = heap_alloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
3109
lstrcpyW(lpstrExt,lpstrPos);
3110
lpstrPos += lstrlenW(lpstrPos) + 1;
3111
3112
/* Add the item at the end of the combo */
3113
SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETITEMDATA, nFilters - 1, (LPARAM)lpstrExt);
3114
3115
/* malformed filters are added anyway... */
3116
if (!*lpstrExt) break;
3117
}
3118
}
3119
3120
/*
3121
* Set the current filter to the one specified
3122
* in the initialisation structure
3123
*/
3124
if (fodInfos->filter || fodInfos->customfilter)
3125
{
3126
LPWSTR lpstrFilter;
3127
3128
/* Check to make sure our index isn't out of bounds. */
3129
if ( fodInfos->ofnInfos->nFilterIndex >
3130
nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
3131
fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
3132
3133
/* set default filter index */
3134
if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
3135
fodInfos->ofnInfos->nFilterIndex = 1;
3136
3137
/* calculate index of Combo Box item */
3138
nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
3139
if (fodInfos->customfilter == NULL)
3140
nFilterIndexCB--;
3141
3142
/* Set the current index selection. */
3143
SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETCURSEL, nFilterIndexCB, 0);
3144
3145
/* Get the corresponding text string from the combo box. */
3146
lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3147
nFilterIndexCB);
3148
3149
if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
3150
lpstrFilter = NULL;
3151
3152
if(lpstrFilter)
3153
{
3154
DWORD len;
3155
CharLowerW(lpstrFilter); /* lowercase */
3156
len = lstrlenW(lpstrFilter)+1;
3157
fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc( len * sizeof(WCHAR) );
3158
lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3159
}
3160
} else
3161
fodInfos->ofnInfos->nFilterIndex = 0;
3162
return S_OK;
3163
}
3164
3165
/***********************************************************************
3166
* FILEDLG95_FILETYPE_OnCommand
3167
*
3168
* WM_COMMAND of the file type combo box
3169
* If the function succeeds, the return value is nonzero.
3170
*/
3171
static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
3172
{
3173
FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3174
3175
switch(wNotifyCode)
3176
{
3177
case CBN_SELENDOK:
3178
{
3179
LPWSTR lpstrFilter;
3180
3181
/* Get the current item of the filetype combo box */
3182
int iItem = SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_GETCURSEL, 0, 0);
3183
3184
/* set the current filter index */
3185
fodInfos->ofnInfos->nFilterIndex = iItem +
3186
(fodInfos->customfilter == NULL ? 1 : 0);
3187
3188
/* Set the current filter with the current selection */
3189
heap_free(fodInfos->ShellInfos.lpstrCurrentFilter);
3190
3191
lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3192
iItem);
3193
if((INT_PTR)lpstrFilter != CB_ERR)
3194
{
3195
DWORD len;
3196
CharLowerW(lpstrFilter); /* lowercase */
3197
len = lstrlenW(lpstrFilter)+1;
3198
fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc( len * sizeof(WCHAR) );
3199
lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3200
if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3201
SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
3202
}
3203
3204
/* Refresh the actual view to display the included items*/
3205
if (fodInfos->Shell.FOIShellView)
3206
IShellView_Refresh(fodInfos->Shell.FOIShellView);
3207
}
3208
}
3209
return FALSE;
3210
}
3211
/***********************************************************************
3212
* FILEDLG95_FILETYPE_SearchExt
3213
*
3214
* searches for an extension in the filetype box
3215
*/
3216
static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
3217
{
3218
int i, iCount;
3219
3220
iCount = SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
3221
3222
TRACE("%s\n", debugstr_w(lpstrExt));
3223
3224
if(iCount != CB_ERR)
3225
{
3226
for(i=0;i<iCount;i++)
3227
{
3228
if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
3229
return i;
3230
}
3231
}
3232
return -1;
3233
}
3234
3235
/***********************************************************************
3236
* FILEDLG95_FILETYPE_Clean
3237
*
3238
* Clean the memory used by the filetype combo box
3239
*/
3240
static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
3241
{
3242
FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3243
int iPos;
3244
int iCount;
3245
3246
iCount = SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_GETCOUNT, 0, 0);
3247
3248
TRACE("\n");
3249
3250
/* Delete each string of the combo and their associated data */
3251
if(iCount != CB_ERR)
3252
{
3253
for(iPos = iCount-1;iPos>=0;iPos--)
3254
{
3255
heap_free((void *)CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
3256
SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_DELETESTRING, iPos, 0);
3257
}
3258
}
3259
/* Current filter */
3260
heap_free(fodInfos->ShellInfos.lpstrCurrentFilter);
3261
}
3262
3263
/***********************************************************************
3264
* FILEDLG95_LOOKIN_Init
3265
*
3266
* Initialisation of the look in combo box
3267
*/
3268
3269
/* Small helper function, to determine if the unixfs shell extension is rooted
3270
* at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3271
*/
3272
static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3273
HKEY hKey;
3274
3275
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3276
L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Desktop\\NameSpace\\"
3277
"{9D20AAE8-0625-44B0-9CA7-71889C2254D9}", 0, KEY_READ, &hKey) != ERROR_SUCCESS)
3278
return FALSE;
3279
3280
RegCloseKey(hKey);
3281
return TRUE;
3282
}
3283
3284
static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
3285
{
3286
IShellFolder *psfRoot, *psfDrives;
3287
IEnumIDList *lpeRoot, *lpeDrives;
3288
LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
3289
HDC hdc;
3290
TEXTMETRICW tm;
3291
LookInInfos *liInfos = heap_alloc_zero(sizeof(*liInfos));
3292
3293
TRACE("%p\n", hwndCombo);
3294
3295
liInfos->iMaxIndentation = 0;
3296
3297
SetPropA(hwndCombo, LookInInfosStr, liInfos);
3298
3299
hdc = GetDC( hwndCombo );
3300
SelectObject( hdc, (HFONT)SendMessageW( hwndCombo, WM_GETFONT, 0, 0 ));
3301
GetTextMetricsW( hdc, &tm );
3302
ReleaseDC( hwndCombo, hdc );
3303
3304
/* set item height for both text field and listbox */
3305
SendMessageW(hwndCombo, CB_SETITEMHEIGHT, -1, max(tm.tmHeight, GetSystemMetrics(SM_CYSMICON)));
3306
SendMessageW(hwndCombo, CB_SETITEMHEIGHT, 0, max(tm.tmHeight, GetSystemMetrics(SM_CYSMICON)));
3307
3308
/* Turn on the extended UI for the combo box like Windows does */
3309
SendMessageW(hwndCombo, CB_SETEXTENDEDUI, TRUE, 0);
3310
3311
/* Initialise data of Desktop folder */
3312
SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
3313
FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3314
ILFree(pidlTmp);
3315
3316
SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
3317
3318
SHGetDesktopFolder(&psfRoot);
3319
3320
if (psfRoot)
3321
{
3322
/* enumerate the contents of the desktop */
3323
if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
3324
{
3325
while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
3326
{
3327
FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3328
3329
/* If the unixfs extension is rooted, we don't expand the drives by default */
3330
if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3331
{
3332
/* special handling for CSIDL_DRIVES */
3333
if (ILIsEqual(pidlTmp, pidlDrives))
3334
{
3335
if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
3336
{
3337
/* enumerate the drives */
3338
if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
3339
{
3340
while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
3341
{
3342
pidlAbsTmp = ILCombine(pidlTmp, pidlTmp1);
3343
FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
3344
ILFree(pidlAbsTmp);
3345
ILFree(pidlTmp1);
3346
}
3347
IEnumIDList_Release(lpeDrives);
3348
}
3349
IShellFolder_Release(psfDrives);
3350
}
3351
}
3352
}
3353
3354
ILFree(pidlTmp);
3355
}
3356
IEnumIDList_Release(lpeRoot);
3357
}
3358
IShellFolder_Release(psfRoot);
3359
}
3360
3361
ILFree(pidlDrives);
3362
}
3363
3364
/***********************************************************************
3365
* FILEDLG95_LOOKIN_DrawItem
3366
*
3367
* WM_DRAWITEM message handler
3368
*/
3369
static LRESULT FILEDLG95_LOOKIN_DrawItem(HWND hwnd, LPDRAWITEMSTRUCT pDIStruct)
3370
{
3371
COLORREF crWin = GetSysColor(COLOR_WINDOW);
3372
COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
3373
COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
3374
RECT rectText, rectIcon, lookin_rect;
3375
SHFILEINFOW sfi;
3376
HIMAGELIST ilItemImage;
3377
int iIndentation;
3378
TEXTMETRICW tm;
3379
LPSFOLDER tmpFolder;
3380
UINT shgfi_flags = SHGFI_PIDL | SHGFI_OPENICON | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME;
3381
UINT icon_width, icon_height;
3382
FileOpenDlgInfos *dialog;
3383
int height;
3384
3385
TRACE("\n");
3386
3387
if(pDIStruct->itemID == -1)
3388
return 0;
3389
3390
if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
3391
pDIStruct->itemID)))
3392
return 0;
3393
3394
3395
icon_width = GetSystemMetrics(SM_CXICON);
3396
icon_height = GetSystemMetrics(SM_CYICON);
3397
if (pDIStruct->rcItem.bottom - pDIStruct->rcItem.top < icon_height)
3398
{
3399
icon_width = GetSystemMetrics(SM_CXSMICON);
3400
icon_height = GetSystemMetrics(SM_CYSMICON);
3401
shgfi_flags |= SHGFI_SMALLICON;
3402
}
3403
3404
ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3405
0, &sfi, sizeof (sfi), shgfi_flags );
3406
3407
/* Is this item selected ? */
3408
if(pDIStruct->itemState & ODS_SELECTED)
3409
{
3410
SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
3411
SetBkColor(pDIStruct->hDC,crHighLight);
3412
FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
3413
}
3414
else
3415
{
3416
SetTextColor(pDIStruct->hDC,crText);
3417
SetBkColor(pDIStruct->hDC,crWin);
3418
FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
3419
}
3420
3421
/* Do not indent item if drawing in the edit of the combo */
3422
if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
3423
iIndentation = 0;
3424
else
3425
iIndentation = tmpFolder->m_iIndent;
3426
3427
/* Draw text and icon */
3428
3429
/* Initialise the icon display area */
3430
rectIcon.left = pDIStruct->rcItem.left + 1 + icon_width/2 * iIndentation;
3431
rectIcon.top = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - icon_height) / 2;
3432
rectIcon.right = rectIcon.left + icon_width + XTEXTOFFSET;
3433
rectIcon.bottom = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + icon_height) / 2;
3434
3435
/* Initialise the text display area */
3436
GetTextMetricsW(pDIStruct->hDC, &tm);
3437
rectText.left = rectIcon.right;
3438
rectText.top =
3439
(pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
3440
rectText.right = pDIStruct->rcItem.right;
3441
rectText.bottom =
3442
(pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
3443
3444
/* Draw the icon from the image list */
3445
ImageList_Draw(ilItemImage,
3446
sfi.iIcon,
3447
pDIStruct->hDC,
3448
rectIcon.left,
3449
rectIcon.top,
3450
ILD_TRANSPARENT );
3451
3452
/* Draw the associated text */
3453
TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3454
3455
dialog = get_filedlg_infoptr(hwnd);
3456
GetWindowRect(dialog->DlgInfos.hwndLookInCB, &lookin_rect);
3457
height = lookin_rect.bottom - lookin_rect.top;
3458
SendMessageW(dialog->DlgInfos.hwndTB, TB_SETBUTTONSIZE, 0, MAKELPARAM(height, height));
3459
3460
return NOERROR;
3461
}
3462
3463
/***********************************************************************
3464
* FILEDLG95_LOOKIN_OnCommand
3465
*
3466
* LookIn combo box WM_COMMAND message handler
3467
* If the function succeeds, the return value is nonzero.
3468
*/
3469
static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3470
{
3471
FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3472
3473
TRACE("%p\n", fodInfos);
3474
3475
switch(wNotifyCode)
3476
{
3477
case CBN_SELENDOK:
3478
{
3479
LPSFOLDER tmpFolder;
3480
int iItem;
3481
3482
iItem = SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_GETCURSEL, 0, 0);
3483
3484
if( iItem == CB_ERR) return FALSE;
3485
3486
if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3487
iItem)))
3488
return FALSE;
3489
3490
3491
if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3492
tmpFolder->pidlItem,
3493
SBSP_ABSOLUTE)))
3494
{
3495
if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3496
SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3497
return TRUE;
3498
}
3499
break;
3500
}
3501
3502
}
3503
return FALSE;
3504
}
3505
3506
/***********************************************************************
3507
* FILEDLG95_LOOKIN_AddItem
3508
*
3509
* Adds an absolute pidl item to the lookin combo box
3510
* returns the index of the inserted item
3511
*/
3512
static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3513
{
3514
LPITEMIDLIST pidlNext;
3515
SHFILEINFOW sfi;
3516
SFOLDER *tmpFolder;
3517
LookInInfos *liInfos;
3518
3519
TRACE("%p, %p, %d\n", hwnd, pidl, iInsertId);
3520
3521
if(!pidl)
3522
return -1;
3523
3524
if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3525
return -1;
3526
3527
tmpFolder = heap_alloc_zero(sizeof(*tmpFolder));
3528
tmpFolder->m_iIndent = 0;
3529
3530
/* Calculate the indentation of the item in the lookin*/
3531
pidlNext = pidl;
3532
while ((pidlNext = ILGetNext(pidlNext)))
3533
{
3534
tmpFolder->m_iIndent++;
3535
}
3536
3537
tmpFolder->pidlItem = ILClone(pidl);
3538
3539
if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3540
liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3541
3542
sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3543
SHGetFileInfoW((LPCWSTR)pidl,
3544
0,
3545
&sfi,
3546
sizeof(sfi),
3547
SHGFI_DISPLAYNAME | SHGFI_PIDL | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3548
3549
TRACE("-- Add %s attr=0x%08lx\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3550
3551
if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3552
{
3553
int iItemID;
3554
3555
TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3556
3557
/* Add the item at the end of the list */
3558
if(iInsertId < 0)
3559
{
3560
iItemID = SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)sfi.szDisplayName);
3561
}
3562
/* Insert the item at the iInsertId position*/
3563
else
3564
{
3565
iItemID = SendMessageW(hwnd, CB_INSERTSTRING, iInsertId, (LPARAM)sfi.szDisplayName);
3566
}
3567
3568
SendMessageW(hwnd, CB_SETITEMDATA, iItemID, (LPARAM)tmpFolder);
3569
return iItemID;
3570
}
3571
3572
ILFree( tmpFolder->pidlItem );
3573
heap_free( tmpFolder );
3574
return -1;
3575
3576
}
3577
3578
/***********************************************************************
3579
* FILEDLG95_LOOKIN_InsertItemAfterParent
3580
*
3581
* Insert an item below its parent
3582
*/
3583
static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3584
{
3585
3586
LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3587
int iParentPos;
3588
3589
TRACE("\n");
3590
3591
if (pidl == pidlParent)
3592
return -1;
3593
3594
iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3595
3596
if(iParentPos < 0)
3597
{
3598
iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3599
}
3600
3601
ILFree(pidlParent);
3602
3603
return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3604
}
3605
3606
/***********************************************************************
3607
* FILEDLG95_LOOKIN_SelectItem
3608
*
3609
* Adds an absolute pidl item to the lookin combo box
3610
* returns the index of the inserted item
3611
*/
3612
int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3613
{
3614
int iItemPos;
3615
LookInInfos *liInfos;
3616
3617
TRACE("%p, %p\n", hwnd, pidl);
3618
3619
iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3620
3621
liInfos = GetPropA(hwnd,LookInInfosStr);
3622
3623
if(iItemPos < 0)
3624
{
3625
while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3626
iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3627
}
3628
3629
else
3630
{
3631
SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3632
while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3633
{
3634
int iRemovedItem;
3635
3636
if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3637
break;
3638
if(iRemovedItem < iItemPos)
3639
iItemPos--;
3640
}
3641
}
3642
3643
SendMessageW(hwnd, CB_SETCURSEL, iItemPos, 0);
3644
liInfos->uSelectedItem = iItemPos;
3645
3646
return 0;
3647
3648
}
3649
3650
/***********************************************************************
3651
* FILEDLG95_LOOKIN_RemoveMostExpandedItem
3652
*
3653
* Remove the item with an expansion level over iExpansionLevel
3654
*/
3655
static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3656
{
3657
int iItemPos;
3658
LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3659
3660
TRACE("\n");
3661
3662
if(liInfos->iMaxIndentation <= 2)
3663
return -1;
3664
3665
if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3666
{
3667
SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3668
ILFree(tmpFolder->pidlItem);
3669
heap_free(tmpFolder);
3670
SendMessageW(hwnd, CB_DELETESTRING, iItemPos, 0);
3671
liInfos->iMaxIndentation--;
3672
3673
return iItemPos;
3674
}
3675
3676
return -1;
3677
}
3678
3679
/***********************************************************************
3680
* FILEDLG95_LOOKIN_SearchItem
3681
*
3682
* Search for pidl in the lookin combo box
3683
* returns the index of the found item
3684
*/
3685
static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3686
{
3687
int i = 0;
3688
int iCount;
3689
3690
iCount = SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
3691
3692
TRACE("0x%08Ix 0x%x\n",searchArg, iSearchMethod);
3693
3694
if (iCount != CB_ERR)
3695
{
3696
for(;i<iCount;i++)
3697
{
3698
LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3699
3700
if (iSearchMethod == SEARCH_PIDL && ILIsEqual((LPITEMIDLIST)searchArg, tmpFolder->pidlItem))
3701
return i;
3702
if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3703
return i;
3704
}
3705
}
3706
3707
return -1;
3708
}
3709
3710
/***********************************************************************
3711
* FILEDLG95_LOOKIN_Clean
3712
*
3713
* Clean the memory used by the lookin combo box
3714
*/
3715
static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3716
{
3717
FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3718
LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3719
int iPos, iCount;
3720
3721
iCount = SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_GETCOUNT, 0, 0);
3722
3723
TRACE("\n");
3724
3725
/* Delete each string of the combo and their associated data */
3726
if (iCount != CB_ERR)
3727
{
3728
for(iPos = iCount-1;iPos>=0;iPos--)
3729
{
3730
SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3731
ILFree(tmpFolder->pidlItem);
3732
heap_free(tmpFolder);
3733
SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_DELETESTRING, iPos, 0);
3734
}
3735
}
3736
3737
/* LookInInfos structure */
3738
heap_free(liInfos);
3739
RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3740
}
3741
3742
/***********************************************************************
3743
* get_def_format
3744
*
3745
* Fill the FORMATETC used in the shell id list
3746
*/
3747
static FORMATETC get_def_format(void)
3748
{
3749
static CLIPFORMAT cfFormat;
3750
FORMATETC formatetc;
3751
3752
if (!cfFormat) cfFormat = RegisterClipboardFormatA(CFSTR_SHELLIDLISTA);
3753
formatetc.cfFormat = cfFormat;
3754
formatetc.ptd = 0;
3755
formatetc.dwAspect = DVASPECT_CONTENT;
3756
formatetc.lindex = -1;
3757
formatetc.tymed = TYMED_HGLOBAL;
3758
return formatetc;
3759
}
3760
3761
/***********************************************************************
3762
* FILEDLG95_FILENAME_FillFromSelection
3763
*
3764
* fills the edit box from the cached DataObject
3765
*/
3766
void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3767
{
3768
FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3769
LPITEMIDLIST pidl;
3770
LPWSTR lpstrAllFiles, lpstrTmp;
3771
UINT nFiles = 0, nFileToOpen, nFileSelected, nAllFilesLength = 0, nThisFileLength, nAllFilesMaxLength;
3772
STGMEDIUM medium;
3773
LPIDA cida;
3774
FORMATETC formatetc = get_def_format();
3775
3776
TRACE("\n");
3777
3778
if (FAILED(IDataObject_GetData(fodInfos->Shell.FOIDataObject, &formatetc, &medium)))
3779
return;
3780
3781
cida = GlobalLock(medium.hGlobal);
3782
nFileSelected = cida->cidl;
3783
3784
/* Allocate a buffer */
3785
nAllFilesMaxLength = MAX_PATH + 3;
3786
lpstrAllFiles = heap_alloc_zero(nAllFilesMaxLength * sizeof(WCHAR));
3787
if (!lpstrAllFiles)
3788
goto ret;
3789
3790
/* Loop through the selection, handle only files (not folders) */
3791
for (nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++)
3792
{
3793
pidl = (LPITEMIDLIST)((LPBYTE)cida + cida->aoffset[nFileToOpen + 1]);
3794
if (pidl)
3795
{
3796
if (!IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl))
3797
{
3798
if (nAllFilesLength + MAX_PATH + 3 > nAllFilesMaxLength)
3799
{
3800
nAllFilesMaxLength *= 2;
3801
lpstrTmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpstrAllFiles, nAllFilesMaxLength * sizeof(WCHAR));
3802
if (!lpstrTmp)
3803
goto ret;
3804
lpstrAllFiles = lpstrTmp;
3805
}
3806
nFiles += 1;
3807
lpstrAllFiles[nAllFilesLength++] = '"';
3808
GetName(fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, lpstrAllFiles + nAllFilesLength);
3809
nThisFileLength = lstrlenW(lpstrAllFiles + nAllFilesLength);
3810
nAllFilesLength += nThisFileLength;
3811
lpstrAllFiles[nAllFilesLength++] = '"';
3812
lpstrAllFiles[nAllFilesLength++] = ' ';
3813
}
3814
}
3815
}
3816
3817
if (nFiles != 0)
3818
{
3819
/* If there's only one file, use the name as-is without quotes */
3820
lpstrTmp = lpstrAllFiles;
3821
if (nFiles == 1)
3822
{
3823
lpstrTmp += 1;
3824
lpstrTmp[nThisFileLength] = 0;
3825
}
3826
SetWindowTextW(fodInfos->DlgInfos.hwndFileName, lpstrTmp);
3827
/* Select the file name like Windows does */
3828
if (filename_is_edit(fodInfos))
3829
SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
3830
}
3831
3832
ret:
3833
heap_free(lpstrAllFiles);
3834
COMCTL32_ReleaseStgMedium(medium);
3835
}
3836
3837
/***********************************************************************
3838
* FILEDLG95_FILENAME_GetFileNames
3839
*
3840
* Copies the filenames to a delimited string list.
3841
*/
3842
static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3843
{
3844
FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3845
UINT nFileCount = 0; /* number of files */
3846
UINT nStrLen = 0; /* length of string in edit control */
3847
LPWSTR lpstrEdit; /* buffer for string from edit control */
3848
3849
TRACE("\n");
3850
3851
/* get the filenames from the filename control */
3852
nStrLen = GetWindowTextLengthW( fodInfos->DlgInfos.hwndFileName );
3853
lpstrEdit = heap_alloc( (nStrLen+1)*sizeof(WCHAR) );
3854
GetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrEdit, nStrLen+1);
3855
3856
TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3857
3858
nFileCount = COMDLG32_SplitFileNames(lpstrEdit, nStrLen, lpstrFileList, sizeUsed);
3859
heap_free(lpstrEdit);
3860
return nFileCount;
3861
}
3862
3863
/*
3864
* DATAOBJECT Helper functions
3865
*/
3866
3867
/***********************************************************************
3868
* COMCTL32_ReleaseStgMedium
3869
*
3870
* like ReleaseStgMedium from ole32
3871
*/
3872
static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3873
{
3874
if(medium.pUnkForRelease)
3875
{
3876
IUnknown_Release(medium.pUnkForRelease);
3877
}
3878
else
3879
{
3880
GlobalUnlock(medium.hGlobal);
3881
GlobalFree(medium.hGlobal);
3882
}
3883
}
3884
3885
/***********************************************************************
3886
* GetPidlFromDataObject
3887
*
3888
* Return pidl(s) by number from the cached DataObject
3889
*
3890
* nPidlIndex=0 gets the fully qualified root path
3891
*/
3892
LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3893
{
3894
3895
STGMEDIUM medium;
3896
FORMATETC formatetc = get_def_format();
3897
LPITEMIDLIST pidl = NULL;
3898
3899
TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3900
3901
if (!doSelected)
3902
return NULL;
3903
3904
/* Get the pidls from IDataObject */
3905
if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3906
{
3907
LPIDA cida = GlobalLock(medium.hGlobal);
3908
if(nPidlIndex <= cida->cidl)
3909
{
3910
pidl = ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3911
}
3912
COMCTL32_ReleaseStgMedium(medium);
3913
}
3914
return pidl;
3915
}
3916
3917
/***********************************************************************
3918
* GetNumSelected
3919
*
3920
* Return the number of selected items in the DataObject.
3921
*
3922
*/
3923
static UINT GetNumSelected( IDataObject *doSelected )
3924
{
3925
UINT retVal = 0;
3926
STGMEDIUM medium;
3927
FORMATETC formatetc = get_def_format();
3928
3929
TRACE("sv=%p\n", doSelected);
3930
3931
if (!doSelected) return 0;
3932
3933
/* Get the pidls from IDataObject */
3934
if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3935
{
3936
LPIDA cida = GlobalLock(medium.hGlobal);
3937
retVal = cida->cidl;
3938
COMCTL32_ReleaseStgMedium(medium);
3939
return retVal;
3940
}
3941
return 0;
3942
}
3943
3944
/*
3945
* TOOLS
3946
*/
3947
3948
/***********************************************************************
3949
* GetName
3950
*
3951
* Get the pidl's display name (relative to folder) and
3952
* put it in lpstrFileName.
3953
*
3954
* Return NOERROR on success,
3955
* E_FAIL otherwise
3956
*/
3957
3958
static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3959
{
3960
STRRET str;
3961
HRESULT hRes;
3962
3963
TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3964
3965
if(!lpsf)
3966
{
3967
SHGetDesktopFolder(&lpsf);
3968
hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3969
IShellFolder_Release(lpsf);
3970
return hRes;
3971
}
3972
3973
/* Get the display name of the pidl relative to the folder */
3974
if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3975
{
3976
return StrRetToBufW(&str, pidl, lpstrFileName, MAX_PATH);
3977
}
3978
return E_FAIL;
3979
}
3980
3981
/***********************************************************************
3982
* GetShellFolderFromPidl
3983
*
3984
* pidlRel is the item pidl relative
3985
* Return the IShellFolder of the absolute pidl
3986
*/
3987
IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3988
{
3989
IShellFolder *psf = NULL,*psfParent;
3990
3991
TRACE("%p\n", pidlAbs);
3992
3993
if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3994
{
3995
psf = psfParent;
3996
if(pidlAbs && pidlAbs->mkid.cb)
3997
{
3998
if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3999
{
4000
IShellFolder_Release(psfParent);
4001
return psf;
4002
}
4003
}
4004
/* return the desktop */
4005
return psfParent;
4006
}
4007
return NULL;
4008
}
4009
4010
/***********************************************************************
4011
* GetParentPidl
4012
*
4013
* Return the LPITEMIDLIST to the parent of the pidl in the list
4014
*/
4015
LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
4016
{
4017
LPITEMIDLIST pidlParent;
4018
4019
TRACE("%p\n", pidl);
4020
4021
pidlParent = ILClone(pidl);
4022
ILRemoveLastID(pidlParent);
4023
4024
return pidlParent;
4025
}
4026
4027
/***********************************************************************
4028
* GetPidlFromName
4029
*
4030
* returns the pidl of the file name relative to folder
4031
* NULL if an error occurred
4032
*/
4033
static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
4034
{
4035
LPITEMIDLIST pidl = NULL;
4036
ULONG ulEaten;
4037
4038
TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
4039
4040
if(!lpcstrFileName) return NULL;
4041
if(!*lpcstrFileName) return NULL;
4042
4043
if(!lpsf)
4044
{
4045
if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
4046
IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
4047
IShellFolder_Release(lpsf);
4048
}
4049
}
4050
else
4051
{
4052
IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
4053
}
4054
return pidl;
4055
}
4056
4057
/*
4058
*/
4059
static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
4060
{
4061
ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
4062
HRESULT ret;
4063
4064
TRACE("%p, %p\n", psf, pidl);
4065
4066
ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
4067
4068
TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
4069
/* see documentation shell 4.1*/
4070
return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
4071
}
4072
4073
/***********************************************************************
4074
* BrowseSelectedFolder
4075
*/
4076
static BOOL BrowseSelectedFolder(HWND hwnd)
4077
{
4078
FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
4079
BOOL bBrowseSelFolder = FALSE;
4080
4081
TRACE("\n");
4082
4083
if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
4084
{
4085
LPITEMIDLIST pidlSelection;
4086
4087
/* get the file selected */
4088
pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
4089
if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
4090
{
4091
if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
4092
pidlSelection, SBSP_RELATIVE ) ) )
4093
{
4094
WCHAR buf[64];
4095
LoadStringW( COMDLG32_hInstance, IDS_PATHNOTEXISTING, buf, ARRAY_SIZE(buf));
4096
MessageBoxW( hwnd, buf, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
4097
}
4098
bBrowseSelFolder = TRUE;
4099
if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
4100
SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
4101
}
4102
ILFree( pidlSelection );
4103
}
4104
4105
return bBrowseSelFolder;
4106
}
4107
4108
static inline BOOL valid_struct_size( DWORD size )
4109
{
4110
return (size == OPENFILENAME_SIZE_VERSION_400W) ||
4111
(size == sizeof( OPENFILENAMEW ));
4112
}
4113
4114
static inline BOOL is_win16_looks(DWORD flags)
4115
{
4116
return (flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE) &&
4117
!(flags & OFN_EXPLORER));
4118
}
4119
4120
/* ------------------ APIs ---------------------- */
4121
4122
/***********************************************************************
4123
* GetOpenFileNameA (COMDLG32.@)
4124
*
4125
* Creates a dialog box for the user to select a file to open.
4126
*
4127
* RETURNS
4128
* TRUE on success: user enters a valid file
4129
* FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4130
*
4131
*/
4132
BOOL WINAPI GetOpenFileNameA(OPENFILENAMEA *ofn)
4133
{
4134
TRACE("flags 0x%08lx\n", ofn->Flags);
4135
4136
if (!valid_struct_size( ofn->lStructSize ))
4137
{
4138
COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4139
return FALSE;
4140
}
4141
4142
/* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4143
if (ofn->Flags & OFN_FILEMUSTEXIST)
4144
ofn->Flags |= OFN_PATHMUSTEXIST;
4145
4146
if (is_win16_looks(ofn->Flags))
4147
return GetFileName31A(ofn, OPEN_DIALOG);
4148
else
4149
{
4150
FileOpenDlgInfos info;
4151
4152
init_filedlg_infoA(ofn, &info);
4153
return GetFileDialog95(&info, OPEN_DIALOG);
4154
}
4155
}
4156
4157
/***********************************************************************
4158
* GetOpenFileNameW (COMDLG32.@)
4159
*
4160
* Creates a dialog box for the user to select a file to open.
4161
*
4162
* RETURNS
4163
* TRUE on success: user enters a valid file
4164
* FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4165
*
4166
*/
4167
BOOL WINAPI GetOpenFileNameW(OPENFILENAMEW *ofn)
4168
{
4169
TRACE("flags 0x%08lx\n", ofn->Flags);
4170
4171
if (!valid_struct_size( ofn->lStructSize ))
4172
{
4173
COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4174
return FALSE;
4175
}
4176
4177
/* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4178
if (ofn->Flags & OFN_FILEMUSTEXIST)
4179
ofn->Flags |= OFN_PATHMUSTEXIST;
4180
4181
if (is_win16_looks(ofn->Flags))
4182
return GetFileName31W(ofn, OPEN_DIALOG);
4183
else
4184
{
4185
FileOpenDlgInfos info;
4186
4187
init_filedlg_infoW(ofn, &info);
4188
return GetFileDialog95(&info, OPEN_DIALOG);
4189
}
4190
}
4191
4192
4193
/***********************************************************************
4194
* GetSaveFileNameA (COMDLG32.@)
4195
*
4196
* Creates a dialog box for the user to select a file to save.
4197
*
4198
* RETURNS
4199
* TRUE on success: user enters a valid file
4200
* FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4201
*
4202
*/
4203
BOOL WINAPI GetSaveFileNameA(OPENFILENAMEA *ofn)
4204
{
4205
if (!valid_struct_size( ofn->lStructSize ))
4206
{
4207
COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4208
return FALSE;
4209
}
4210
4211
if (is_win16_looks(ofn->Flags))
4212
return GetFileName31A(ofn, SAVE_DIALOG);
4213
else
4214
{
4215
FileOpenDlgInfos info;
4216
4217
init_filedlg_infoA(ofn, &info);
4218
return GetFileDialog95(&info, SAVE_DIALOG);
4219
}
4220
}
4221
4222
/***********************************************************************
4223
* GetSaveFileNameW (COMDLG32.@)
4224
*
4225
* Creates a dialog box for the user to select a file to save.
4226
*
4227
* RETURNS
4228
* TRUE on success: user enters a valid file
4229
* FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4230
*
4231
*/
4232
BOOL WINAPI GetSaveFileNameW(
4233
LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4234
{
4235
if (!valid_struct_size( ofn->lStructSize ))
4236
{
4237
COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4238
return FALSE;
4239
}
4240
4241
if (is_win16_looks(ofn->Flags))
4242
return GetFileName31W(ofn, SAVE_DIALOG);
4243
else
4244
{
4245
FileOpenDlgInfos info;
4246
4247
init_filedlg_infoW(ofn, &info);
4248
return GetFileDialog95(&info, SAVE_DIALOG);
4249
}
4250
}
4251
4252
/***********************************************************************
4253
* GetFileTitleA (COMDLG32.@)
4254
*
4255
* See GetFileTitleW.
4256
*/
4257
short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4258
{
4259
int ret;
4260
UNICODE_STRING strWFile;
4261
LPWSTR lpWTitle;
4262
4263
RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4264
lpWTitle = heap_alloc(cbBuf * sizeof(WCHAR));
4265
ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4266
if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4267
RtlFreeUnicodeString( &strWFile );
4268
heap_free( lpWTitle );
4269
return ret;
4270
}
4271
4272
4273
/***********************************************************************
4274
* GetFileTitleW (COMDLG32.@)
4275
*
4276
* Get the name of a file.
4277
*
4278
* PARAMS
4279
* lpFile [I] name and location of file
4280
* lpTitle [O] returned file name
4281
* cbBuf [I] buffer size of lpTitle
4282
*
4283
* RETURNS
4284
* Success: zero
4285
* Failure: negative number.
4286
*/
4287
short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4288
{
4289
int i, len;
4290
TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4291
4292
if(lpFile == NULL || lpTitle == NULL)
4293
return -1;
4294
4295
len = lstrlenW(lpFile);
4296
4297
if (len == 0)
4298
return -1;
4299
4300
if(wcspbrk(lpFile, L"*[]"))
4301
return -1;
4302
4303
len--;
4304
4305
if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4306
return -1;
4307
4308
for(i = len; i >= 0; i--)
4309
{
4310
if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4311
{
4312
i++;
4313
break;
4314
}
4315
}
4316
4317
if(i == -1)
4318
i++;
4319
4320
TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4321
4322
len = lstrlenW(lpFile+i)+1;
4323
if(cbBuf < len)
4324
return len;
4325
4326
lstrcpyW(lpTitle, &lpFile[i]);
4327
return 0;
4328
}
4329
4330