OWLNext    7.0
Borland's Object Windows Library for the modern age
Loading...
Searching...
No Matches
opensave.cpp
Go to the documentation of this file.
1//----------------------------------------------------------------------------
2// ObjectWindows
3// Copyright (c) 1992, 1996 by Borland International, All Rights Reserved
4//
5/// \file
6/// Implementation of OpenSave abstract, FileOpen, FileSave Common Dialog
7/// classes
8//----------------------------------------------------------------------------
9#include <owl/pch.h>
10#include <owl/opensave.h>
11#include <owl/commctrl.h>
12
13namespace owl {
14
16
17
18//
19/// Constructs a TOpenSaveDialog::TData structure.
20//
22 uint32 flags,
24 LPTSTR, // customFilter, // Dummy for backward compatibility.
27 int maxPath,
28 int filterIndex,
30 )
31 : Flags(flags),
32 FlagsEx(flagsEx),
33 Error(0),
34 FileName(nullptr),
35 Filter(nullptr),
36 FilterIndex(filterIndex),
37 InitialDir(initialDir),
38 DefExt(defExt),
39 MaxPath(maxPath ? maxPath : _MAX_PATH)
40{
41 FileName = new tchar[MaxPath];
42 *FileName = 0;
44
45 // OFN_EXPLORER implies long names, but we include OFN_LONGNAMES in case OFN_EXPLORER is turned
46 // off by user code later.
47 //
49}
50
51//
52/// String-aware overload
53/// TODO: Add string support for all parameters.
54//
56 uint32 flags,
57 const tstring& filter,
58 LPTSTR, // customFilter, // Dummy for backward compatibility.
61 int maxPath,
62 int filterIndex,
64 )
65 : Flags(flags),
66 FlagsEx(flagsEx),
67 Error(0),
68 FileName(nullptr),
69 Filter(nullptr),
70 FilterIndex(filterIndex),
71 InitialDir(initialDir),
72 DefExt(defExt),
73 MaxPath(maxPath ? maxPath : _MAX_PATH)
74{
75 FileName = new tchar[MaxPath];
76 *FileName = 0;
79}
80
81//
82//
83//
85 : Flags(src.Flags),
86 FlagsEx(src.FlagsEx),
87 Error(src.Error),
88 FileName(nullptr),
89 Filter(nullptr),
90 FilterIndex(src.FilterIndex),
91 InitialDir(src.InitialDir),
92 DefExt(src.DefExt),
93 MaxPath(src.MaxPath)
94{
95 FileName = strnewdup(src.FileName, MaxPath);
96 SetFilter(src.Filter);
97}
98
99//
100/// Destructs a TOpenSaveDialog::TData structure.
101//
103{
104 delete[] FileName;
105 delete[] Filter;
106}
107
108//
109//
110//
113{
114 Flags = src.Flags;
115 FlagsEx = src.FlagsEx;
116 Error = src.Error;
117 FilterIndex = src.FilterIndex;
118 InitialDir = src.InitialDir;
119 DefExt = src.DefExt;
120 MaxPath = src.MaxPath;
121
122 delete[] FileName;
123 FileName = strnewdup(src.FileName, MaxPath);
124
125 SetFilter(src.Filter);
126
127 return *this;
128}
129
130//
131/// Makes a copy of the filter list used to display the file names.
132//
133/// Set the file list box filter strings. Translates '|'s into 0s so that the
134/// string can be kept as a resource with imbeded '|'s like:
135/// \code
136/// "Text Files(*.txt)|*.TXT|All Files(*.*)|*.*|"
137/// \endcode
138/// Can also handle already processed filter strings.
139//
140void
142{
143 // Copy filter string
144 //
145 if (filter) {
146 delete[] Filter;
147 if (_tcschr(filter, _T('|'))) {
148 uint len = static_cast<uint>(::_tcslen(filter)) + 2; // one for each terminating 0
149 Filter = ::_tcscpy(new tchar[len], filter);
150 Filter[len-1] = 0; // in case trailing '|' is missing
151 }
152 else {
153 LPCTSTR p = filter;
154 while (*p)
155 p += ::_tcslen(p) + 1; // scan for 00 at end
156 uint len = uint(p - filter) + 1; // one more for last 0
157 Filter = new tchar[len];
158 memcpy(Filter, filter, sizeof(tchar) * len);
159 }
160 }
161 // Stomp |s with 0s
162 //
163 if (Filter) {
164 for (TCharIterator<tchar> i(Filter); ; i++) {
165 if (!*i.Current())
166 break;
167 if (*i.Current() == _T('|'))
168 *i.Current() = 0;
169 }
170 }
171}
172
173
174//----------------------------------------------------------------------------
175
178
179const uint TOpenSaveDialog::ShareViMsgId = ::RegisterWindowMessage(SHAREVISTRING);
180
181
182//
183/// Initializes a TOpenSaveDialog object with the current resource ID.
184//
185void
187{
188 memset(&ofn, 0, sizeof(OPENFILENAME));
189#if defined(OPENFILENAME_SIZE_VERSION_400)
190 ofn.lStructSize = TSystem::GetMajorVersion() < 5 ?
192#else
193 ofn.lStructSize = sizeof(OPENFILENAME);
194#endif
195 ofn.hwndOwner = GetParentO() ? GetParentO()->GetHandle() : nullptr;
196 ofn.hInstance = *GetModule();
197 ofn.Flags = OFN_ENABLEHOOK | Data.Flags;
198 if (templateId) {
199 ofn.lpTemplateName = templateId;
200 ofn.Flags |= OFN_ENABLETEMPLATE;
201 }
202 else
203 ofn.Flags &= ~OFN_ENABLETEMPLATE;
204#if WINVER >= 0x500 && !defined(WINELIB)
205 ofn.FlagsEx = Data.FlagsEx;
206#endif
207 ofn.lpfnHook = nullptr;
208
209 ofn.lpstrFilter = Data.Filter;
210 ofn.nFilterIndex = Data.FilterIndex;
211 ofn.lpstrFile = Data.FileName;
212 ofn.nMaxFile = Data.MaxPath;
213 ofn.lpstrInitialDir = Data.InitialDir;
214 ofn.lpstrDefExt = Data.DefExt;
215}
216
217//
218/// Constructs an open save dialog box object with the supplied parent window, data,
219/// resource ID, title, and current module object.
220//
222:
223 TCommonDialog(parent, nullptr, module),
224 Data(data)
225{
226}
227
228//
229//
230//
232 TData& data,
235 TModule* module)
236:
237 TCommonDialog(parent, nullptr, module),
238 Data(data),
239 Title(title ? title : _T(""))
240{
242 ofn.lpstrTitle = title ? &Title[0] : nullptr;
243}
244
245//
246/// String-aware overload
247//
249 TWindow* parent,
250 TData& data,
252 const tstring& title,
253 TModule* module)
254:
255 TCommonDialog(parent, nullptr, module),
256 Data(data),
257 Title(title)
258{
260 ofn.lpstrTitle = &Title[0];
261}
262
263//
264/// Handles CDN_SHAREVIOLATION and the older SHAREVISTRING registered message.
265/// Calls the base implementation to handle all other messages.
266//
269{
270 const bool explorerStyle = ofn.Flags & OFN_EXPLORER;
271
272 // First check for the new message.
273 //
274 TNotify* n = (msg == WM_NOTIFY) ? reinterpret_cast<TNotify*>(param2) : nullptr;
275 if (n && n->code == CDN_SHAREVIOLATION)
276 {
277 WARN(!explorerStyle, _T("CDN_SHAREVIOLATION was sent to old-style dialog."));
278 int r = ShareViolation();
279
280 // The documentation for CDN_SHAREVIOLATION states that 0 should be
281 // returned to get the standard warning message for a sharing violation.
282 // It does not list OFN_SHAREWARN as a valid DWL_MSGRESULT value.
283 // Note that this causes the old SHAREVISTRING to be sent; see below.
284 //
285 if (r == OFN_SHAREWARN)
286 return 0;
287
289 WARN(r != OFN_SHAREFALLTHROUGH && r != OFN_SHARENOWARN, _T("ShareViolation returned undefined value: ") << r);
290 return SetMsgResult(r);
291 }
292
293 // Now check for the old message.
294 //
295 else if (msg == TOpenSaveDialog::ShareViMsgId)
296 {
297 int r = ShareViolation();
298
299 // Do not handle SHAREVISTRING for Explorer-style dialogs.
300 // The message is a result of the default handling for CDN_SHAREVIOLATION, i.e.
301 // when CDN_SHAREVIOLATION returns 0 then SHAREVISTRING is sent.
302 //
303 if (explorerStyle)
304 {
305 WARN(r != OFN_SHAREWARN, _T("ShareViolation returned unexpected value in Explorer-style dialog:") << r);
306 return 0;
307 }
308
311 _T("ShareViolation returned undefined value: ") << r);
312
313 // The documentation for SHAREVISTRING states that the result should be
314 // returned directly, rather than through DWL_MSGRESULT.
315 //
316 return r;
317 }
318
319 // If we get here, pass the message on to the base.
320 //
322}
323
324//
325/// If a sharing violation occurs when a file is opened or saved, ShareViolation is
326/// called to obtain a response. The default return value is OFN_SHAREWARN. Other
327/// sharing violation responses are listed in the following table.
328/// - \c \b OFN_SHAREFALLTHROUGH Specifies that the file name can be used and that the
329/// dialog box should return it to the application.
330/// - \c \b OFN_SHARENOWARN Instructs the dialog box to perform no further action with
331/// the file name and not to warn the user of the situation.
332/// - \c \b OFN_SHAREWARN This is the default response that is defined as 0. Instructs the
333/// dialog box to display a standard warning message.
334//
335int
340
341//----------------------------------------------------------------------------
342
343//
344/// Constructs and initializes the TFileOpen object based on information in the
345/// TOpenSaveDialog::TData data structure. The parent argument points to the dialog
346/// box's parent window. data is a reference to the TData object. templateID is the
347/// ID for a custom template. title is an optional title. module points to the
348/// module instance.
349//
351 TData& data,
354 TModule* module)
355:
356 TOpenSaveDialog(parent, data, templateId, title, module)
357{
358}
359
360//
361/// Creates the TFileOpenDialog object.
362//
363int
365{
366 ofn.lpfnHook = LPOFNHOOKPROC(StdDlgProc);
367 int ret = GetOpenFileName(&ofn);
368 Data.Error = CommDlgExtendedError();
369 if (ret) {
370 Data.Flags = ofn.Flags;
371 Data.FilterIndex = static_cast<int>(ofn.nFilterIndex);
372 }
373 return ret ? IDOK : IDCANCEL;
374}
375
376
377//----------------------------------------------------------------------------
378
379//
380/// Constructs and initializes the TFileOpen object based on the
381/// TOpenSaveDialog::TData structure, which contains information about the file
382/// name, file directory, and file name search filers.
383//
385 TData& data,
388 TModule* module)
389:
390 TOpenSaveDialog(parent, data, templateId, title, module)
391{
392}
393
394//
395/// Creates the TFileSaveDialog object.
396//
397int
399{
400 ofn.lpfnHook = LPOFNHOOKPROC(StdDlgProc);
401 int ret = GetSaveFileName(&ofn);
402 Data.Error = CommDlgExtendedError();
403 if (ret) {
404 Data.Flags = ofn.Flags;
405 Data.FilterIndex = ofn.nFilterIndex;
406 }
407 return ret ? IDOK : IDCANCEL;
408}
409
410
411//
412//
413//
414void
416{
417 is >> Flags;
418#if defined(UNICODE)
420
421 char* fileName = is.readString();
422 char* filter = is.freadString();
423 char* customFilter = is.freadString(); // Dummy for backward compatibility.
424 if (customFilter) delete [] customFilter; // Discard dummy.
425
428
429 delete[] fileName;
430 delete[] filter;
431
432 is >> FilterIndex;
433
434 char* initDir = is.freadString();
435 char* defExt = is.freadString();
436
439
440 delete[] initDir;
441 delete[] defExt;
442
443#else
444 FileName = is.readString();
445 Filter = is.freadString();
446 const auto customFilter = is.freadString(); // Dummy for backward compatibility.
447 if (customFilter) delete[] customFilter; // Discard dummy.
448 is >> FilterIndex;
449 InitialDir = is.freadString();
450 DefExt = is.freadString();
451#endif
452 is >> FlagsEx;
453}
454
455//
456//
457//
458void
460{
462
463 os << Flags;
464 os.writeString(_W2A(FileName));
465 os.fwriteString(_W2A(Filter));
466 const auto customFilter = nullptr; // Dummy for backward compatibility.
467 os.fwriteString(customFilter);
468 os << FilterIndex;
469 os.fwriteString(_W2A(InitialDir));
470 os.fwriteString(_W2A(DefExt));
471 os << FlagsEx;
472}
473
474//
475/// Returns a vector containing the full paths of every file entry in member FileName.
476/// This function is only useful in conjunction with a multi-selection TFileOpenDialog using the
477/// Explorer style.
478///
479/// \note It is assumed that the buffer pointed to by member FileName contains a null-separated
480/// list of file names terminated by two null characters, as will be the case if filled in by a
481/// multi-selection Explorer-style TFileOpenDialog. Note that this function does not work unless
482/// the flags OFN_EXPLORER and OFN_ALLOWMULTISELECT were both set!
483///
484/// Usage:
485///
486/// \code
487/// void TBmpViewWindow::CmFileOpen()
488/// {
489/// TOpenSaveDialog::TData data
490/// {
491/// OFN_EXPLORER | OFN_ALLOWMULTISELECT | OFN_FILEMUSTEXIST, // flags
492/// "Bitmap Files (*.bmp)|*.bmp", // filter
493/// nullptr, // customFilter
494/// nullptr, // initialDir
495/// nullptr, // defExt
496/// 65536 // maxPath (ample buffer space for multiple selections)
497/// };
498/// TFileOpenDialog dlg{this, data};
499/// const auto r = dlg.Execute();
500/// if (CommDlgExtendedError() == FNERR_BUFFERTOOSMALL)
501/// {
502/// MessageBox("Buffer too small!", "File Open Error", MB_OK | MB_ICONEXCLAMATION);
503/// return;
504/// }
505/// if (r == IDOK)
506/// for (const auto& f : data.GetFileNames())
507/// OpenFile(f);
508/// }
509/// \endcode
510///
511/// \sa http://docs.microsoft.com/en-us/windows/desktop/api/Commdlg/ns-commdlg-tagofna
512//
514{
515 PRECONDITION((Flags & OFN_EXPLORER) && (Flags & OFN_ALLOWMULTISELECT));
516
517 auto v = std::vector<tstring>{};
518 auto p = FileName;
519 const auto d = tstring{p};
520 p += d.size() + 1;
521 CHECK(static_cast<int>(p - FileName) < MaxPath);
522
523 // NOTE: We assume double null-termination here, even for a single file!
524 //
525 if (*p == _T('\0'))
526 {
527 // We have a single entry, being the full path to the file.
528 //
529 v.push_back(d);
530 }
531 else
532 {
533 // We have multiple entries following the directory path, each being the bare file name without a path.
534 // Compose the full path to each file by prepending the directory path.
535 //
536 while (*p != _T('\0'))
537 {
538 const auto n = tstring{p};
539 const auto f = d + _T('\\') + n;
540 v.push_back(f);
541 p += n.size() + 1;
542 CHECK(static_cast<int>(p - FileName) < MaxPath);
543 }
544 }
545 return v;
546}
547
548} // OWL namespace
549/* ========================================================================== */
550
#define CHECK(condition)
Definition checks.h:239
#define WARN(condition, message)
Definition checks.h:273
#define PRECONDITION(condition)
Definition checks.h:227
Derived from TDialog, TCommonDialog is the abstract base class for TCommonDialog objects.
Definition commdial.h:62
bool SetMsgResult(TResult result)
Sets the dialog procedure message result (DWLP_MSGRESULT) and returns true.
Definition dialog.h:282
virtual INT_PTR DialogFunction(TMsgId, TParam1, TParam2)
Override this to process messages within the dialog function.
Definition dialog.cpp:353
static INT_PTR CALLBACK StdDlgProc(HWND, UINT, WPARAM, LPARAM) noexcept
Callback procs for hooking TDialog to native window.
Definition dialog.cpp:440
int DoExecute()
Creates the TFileOpenDialog object.
Definition opensave.cpp:364
TFileOpenDialog(TWindow *parent, TData &data, TResId templateId=0, LPCTSTR title=nullptr, TModule *module=nullptr)
Constructs and initializes the TFileOpen object based on information in the TOpenSaveDialog::TData da...
Definition opensave.cpp:350
int DoExecute()
Creates the TFileSaveDialog object.
Definition opensave.cpp:398
TFileSaveDialog(TWindow *parent, TData &data, TResId templateId=0, LPCTSTR title=nullptr, TModule *module=nullptr)
Constructs and initializes the TFileOpen object based on the TOpenSaveDialog::TData structure,...
Definition opensave.cpp:384
ObjectWindows dynamic-link libraries (DLLs) construct an instance of TModule, which acts as an object...
Definition module.h:75
TNotify is a thin wrapper around the NMHDR structure.
Definition commctrl.h:91
TOpenSaveDialog structure contains information about the user's file open or save selection.
Definition opensave.h:44
TData & operator=(const TData &src)
Definition opensave.cpp:112
TCHAR * FileName
Holds the name of the file to be saved or opened.
Definition opensave.h:112
TData(uint32 flags=0, LPCTSTR filter=nullptr, TCHAR *customFilter=nullptr, LPCTSTR initialDir=nullptr, LPCTSTR defExt=nullptr, int maxPath=0, int filterIndex=0, uint32 flagsEx=0)
Constructs a TOpenSaveDialog::TData structure.
Definition opensave.cpp:21
int FilterIndex
FilterIndex indicates which filter to use initially when displaying file names.
Definition opensave.h:119
void Read(ipstream &is)
Definition opensave.cpp:415
LPCTSTR InitialDir
Directory to use initially when displaying file names.
Definition opensave.h:123
~TData()
Destructs a TOpenSaveDialog::TData structure.
Definition opensave.cpp:102
uint32 Flags
Flag contains one or more of the following constants:
Definition opensave.h:80
void Write(opstream &os)
Definition opensave.cpp:459
TCHAR * Filter
Filter holds the filter to use initially when displaying file names.
Definition opensave.h:116
LPCTSTR DefExt
Default extension to use when saving file names.
Definition opensave.h:127
auto GetFileNames() const -> std::vector< tstring >
Returns a vector containing the full paths of every file entry in member FileName.
Definition opensave.cpp:513
void SetFilter(LPCTSTR filter=nullptr)
Makes a copy of the filter list used to display the file names.
Definition opensave.cpp:141
TOpenSaveDialog is the base class for modal dialogs that let you open and save a file under a specifi...
Definition opensave.h:34
TOpenSaveDialog(TWindow *parent, TData &data, TResId templateId=0, LPCTSTR title=nullptr, TModule *module=nullptr)
Definition opensave.cpp:231
auto DialogFunction(TMsgId, TParam1, TParam2) -> INT_PTR override
Handles CDN_SHAREVIOLATION and the older SHAREVISTRING registered message.
Definition opensave.cpp:268
virtual int ShareViolation()
If a sharing violation occurs when a file is opened or saved, ShareViolation is called to obtain a re...
Definition opensave.cpp:336
void Init(TResId templateId)
Initializes a TOpenSaveDialog object with the current resource ID.
Definition opensave.cpp:186
static uint GetMajorVersion()
Definition system.cpp:81
TWindow, derived from TEventHandler and TStreamableBase, provides window-specific behavior and encaps...
Definition window.h:414
TWindow * GetParentO() const
Return the OWL's parent for this window.
Definition window.h:2006
TModule * GetModule() const
Returns a pointer to the module object.
Definition window.h:1841
HWND GetHandle() const
Returns the handle of the window.
Definition window.h:2020
ipstream, a specialized input stream derivative of pstream, is the base class for reading (extracting...
Definition objstrm.h:391
Base class for writing streamable objects.
Definition objstrm.h:480
Definition of classes for CommonControl encapsulation.
#define _tcscpy
Definition cygwin.h:79
#define _MAX_PATH
Definition cygwin.h:97
#define _tcslen
Definition cygwin.h:74
#define _T(x)
Definition cygwin.h:51
#define _tcschr
Definition cygwin.h:85
#define DEFINE_RESPONSE_TABLE1(cls, base)
Macro to define a response table for a class with one base.
Definition eventhan.h:492
#define _W2A(lpw)
Definition memory.h:219
char * strnewdup(const char *s, size_t minAllocSize=0)
Definition memory.cpp:25
#define _A2W(lpw)
Definition memory.h:220
#define _USES_CONVERSION
Definition memory.h:217
Object Windows Library (OWLNext Core)
Definition animctrl.h:22
UINT TMsgId
Message ID type.
Definition dispatch.h:53
unsigned long uint32
Definition number.h:34
LPARAM TParam2
Second parameter type.
Definition dispatch.h:55
WPARAM TParam1
First parameter type.
Definition dispatch.h:54
OWL_DIAGINFO
Definition animctrl.cpp:14
END_RESPONSE_TABLE
Definition button.cpp:26
std::string tstring
Definition defs.h:79
unsigned int uint
Definition number.h:25
Definition of TOpenSave abstract, TFileOpen, TFileSave common Dialog classes.
#define OWL_STRICT
Definition defs.h:220