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