OWLNext    7.0
Borland's Object Windows Library for the modern age
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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