Make storing non-trivial data in wxThreadSpecificInfo possible.
[wxWidgets.git] / src / msw / filedlg.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/filedlg.cpp
3 // Purpose: wxFileDialog
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 01/02/97
7 // Copyright: (c) Julian Smart
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 #if wxUSE_FILEDLG && !(defined(__SMARTPHONE__) && defined(__WXWINCE__))
27
28 #include "wx/filedlg.h"
29
30 #ifndef WX_PRECOMP
31 #include "wx/msw/wrapcdlg.h"
32 #include "wx/msw/missing.h"
33 #include "wx/utils.h"
34 #include "wx/msgdlg.h"
35 #include "wx/filefn.h"
36 #include "wx/intl.h"
37 #include "wx/log.h"
38 #include "wx/app.h"
39 #include "wx/math.h"
40 #endif
41
42 #include <stdlib.h>
43 #include <string.h>
44
45 #include "wx/dynlib.h"
46 #include "wx/filename.h"
47 #include "wx/scopeguard.h"
48 #include "wx/tokenzr.h"
49 #include "wx/modalhook.h"
50
51 // ----------------------------------------------------------------------------
52 // constants
53 // ----------------------------------------------------------------------------
54
55 #ifdef __WIN32__
56 # define wxMAXPATH 65534
57 #else
58 # define wxMAXPATH 1024
59 #endif
60
61 # define wxMAXFILE 1024
62
63 # define wxMAXEXT 5
64
65 // ----------------------------------------------------------------------------
66 // globals
67 // ----------------------------------------------------------------------------
68
69 // standard dialog size for the old Windows systems where the dialog wasn't
70 // resizable
71 static wxRect gs_rectDialog(0, 0, 428, 266);
72
73 // ============================================================================
74 // implementation
75 // ============================================================================
76
77 IMPLEMENT_CLASS(wxFileDialog, wxFileDialogBase)
78
79 // ----------------------------------------------------------------------------
80
81 namespace
82 {
83
84 #if wxUSE_DYNLIB_CLASS
85
86 typedef BOOL (WINAPI *GetProcessUserModeExceptionPolicy_t)(LPDWORD);
87 typedef BOOL (WINAPI *SetProcessUserModeExceptionPolicy_t)(DWORD);
88
89 GetProcessUserModeExceptionPolicy_t gs_pfnGetProcessUserModeExceptionPolicy
90 = (GetProcessUserModeExceptionPolicy_t) -1;
91
92 SetProcessUserModeExceptionPolicy_t gs_pfnSetProcessUserModeExceptionPolicy
93 = (SetProcessUserModeExceptionPolicy_t) -1;
94
95 DWORD gs_oldExceptionPolicyFlags = 0;
96
97 bool gs_changedPolicy = false;
98
99 #endif // #if wxUSE_DYNLIB_CLASS
100
101 /*
102 Since Windows 7 by default (callback) exceptions aren't swallowed anymore
103 with native x64 applications. Exceptions can occur in a file dialog when
104 using the hook procedure in combination with third-party utilities.
105 Since Windows 7 SP1 the swallowing of exceptions can be enabled again
106 by using SetProcessUserModeExceptionPolicy.
107 */
108 void ChangeExceptionPolicy()
109 {
110 #if wxUSE_DYNLIB_CLASS
111 gs_changedPolicy = false;
112
113 wxLoadedDLL dllKernel32(wxT("kernel32.dll"));
114
115 if ( gs_pfnGetProcessUserModeExceptionPolicy
116 == (GetProcessUserModeExceptionPolicy_t) -1)
117 {
118 wxDL_INIT_FUNC(gs_pfn, GetProcessUserModeExceptionPolicy, dllKernel32);
119 wxDL_INIT_FUNC(gs_pfn, SetProcessUserModeExceptionPolicy, dllKernel32);
120 }
121
122 if ( !gs_pfnGetProcessUserModeExceptionPolicy
123 || !gs_pfnSetProcessUserModeExceptionPolicy
124 || !gs_pfnGetProcessUserModeExceptionPolicy(&gs_oldExceptionPolicyFlags) )
125 {
126 return;
127 }
128
129 if ( gs_pfnSetProcessUserModeExceptionPolicy(gs_oldExceptionPolicyFlags
130 | 0x1 /* PROCESS_CALLBACK_FILTER_ENABLED */ ) )
131 {
132 gs_changedPolicy = true;
133 }
134
135 #endif // wxUSE_DYNLIB_CLASS
136 }
137
138 void RestoreExceptionPolicy()
139 {
140 #if wxUSE_DYNLIB_CLASS
141 if (gs_changedPolicy)
142 {
143 gs_changedPolicy = false;
144 (void) gs_pfnSetProcessUserModeExceptionPolicy(gs_oldExceptionPolicyFlags);
145 }
146 #endif // wxUSE_DYNLIB_CLASS
147 }
148
149 } // unnamed namespace
150
151 // ----------------------------------------------------------------------------
152 // hook function for moving the dialog
153 // ----------------------------------------------------------------------------
154
155 UINT_PTR APIENTRY
156 wxFileDialogHookFunction(HWND hDlg,
157 UINT iMsg,
158 WPARAM WXUNUSED(wParam),
159 LPARAM lParam)
160 {
161 switch ( iMsg )
162 {
163 #ifndef __WXWINCE__
164 case WM_INITDIALOG:
165 {
166 OPENFILENAME* ofn = reinterpret_cast<OPENFILENAME *>(lParam);
167 reinterpret_cast<wxFileDialog *>(ofn->lCustData)
168 ->MSWOnInitDialogHook((WXHWND)hDlg);
169 }
170 break;
171 #endif // __WXWINCE__
172
173 case WM_NOTIFY:
174 {
175 OFNOTIFY* const
176 pNotifyCode = reinterpret_cast<OFNOTIFY *>(lParam);
177 wxFileDialog* const
178 dialog = reinterpret_cast<wxFileDialog *>(
179 pNotifyCode->lpOFN->lCustData
180 );
181
182 switch ( pNotifyCode->hdr.code )
183 {
184 case CDN_INITDONE:
185 dialog->MSWOnInitDone((WXHWND)hDlg);
186 break;
187
188 case CDN_SELCHANGE:
189 dialog->MSWOnSelChange((WXHWND)hDlg);
190 break;
191 }
192 }
193 break;
194
195 case WM_DESTROY:
196 // reuse the position used for the dialog the next time by default
197 //
198 // NB: at least under Windows 2003 this is useless as after the
199 // first time it's shown the dialog always remembers its size
200 // and position itself and ignores any later SetWindowPos calls
201 wxCopyRECTToRect(wxGetWindowRect(::GetParent(hDlg)), gs_rectDialog);
202 break;
203 }
204
205 // do the default processing
206 return 0;
207 }
208
209 // ----------------------------------------------------------------------------
210 // wxFileDialog
211 // ----------------------------------------------------------------------------
212
213 wxFileDialog::wxFileDialog(wxWindow *parent,
214 const wxString& message,
215 const wxString& defaultDir,
216 const wxString& defaultFileName,
217 const wxString& wildCard,
218 long style,
219 const wxPoint& pos,
220 const wxSize& sz,
221 const wxString& name)
222 : wxFileDialogBase(parent, message, defaultDir, defaultFileName,
223 wildCard, style, pos, sz, name)
224
225 {
226 // NB: all style checks are done by wxFileDialogBase::Create
227
228 m_bMovedWindow = false;
229 m_centreDir = 0;
230
231 // Must set to zero, otherwise the wx routines won't size the window
232 // the second time you call the file dialog, because it thinks it is
233 // already at the requested size.. (when centering)
234 gs_rectDialog.x =
235 gs_rectDialog.y = 0;
236 }
237
238 void wxFileDialog::GetPaths(wxArrayString& paths) const
239 {
240 paths.Empty();
241
242 wxString dir(m_dir);
243 if ( m_dir.empty() || m_dir.Last() != wxT('\\') )
244 dir += wxT('\\');
245
246 size_t count = m_fileNames.GetCount();
247 for ( size_t n = 0; n < count; n++ )
248 {
249 if (wxFileName(m_fileNames[n]).IsAbsolute())
250 paths.Add(m_fileNames[n]);
251 else
252 paths.Add(dir + m_fileNames[n]);
253 }
254 }
255
256 void wxFileDialog::GetFilenames(wxArrayString& files) const
257 {
258 files = m_fileNames;
259 }
260
261 void wxFileDialog::DoGetPosition(int *x, int *y) const
262 {
263 if ( x )
264 *x = gs_rectDialog.x;
265 if ( y )
266 *y = gs_rectDialog.y;
267 }
268
269 void wxFileDialog::DoGetSize(int *width, int *height) const
270 {
271 if ( width )
272 *width = gs_rectDialog.width;
273 if ( height )
274 *height = gs_rectDialog.height;
275 }
276
277 void wxFileDialog::DoMoveWindow(int x, int y, int WXUNUSED(w), int WXUNUSED(h))
278 {
279 gs_rectDialog.x = x;
280 gs_rectDialog.y = y;
281
282 // our HWND is only set when we're called from MSWOnInitDone(), test if
283 // this is the case
284 HWND hwnd = GetHwnd();
285 if ( hwnd )
286 {
287 // size of the dialog can't be changed because the controls are not
288 // laid out correctly then
289 ::SetWindowPos(hwnd, HWND_TOP, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
290 }
291 else // just remember that we were requested to move the window
292 {
293 m_bMovedWindow = true;
294
295 // if Centre() had been called before, it shouldn't be taken into
296 // account now
297 m_centreDir = 0;
298 }
299 }
300
301 void wxFileDialog::DoCentre(int dir)
302 {
303 m_centreDir = dir;
304 m_bMovedWindow = true;
305
306 // it's unnecessary to do anything else at this stage as we'll redo it in
307 // MSWOnInitDone() anyhow
308 }
309
310 void wxFileDialog::MSWOnInitDone(WXHWND hDlg)
311 {
312 // note the dialog is the parent window: hDlg is a child of it when
313 // OFN_EXPLORER is used
314 HWND hFileDlg = ::GetParent((HWND)hDlg);
315
316 // set HWND so that our DoMoveWindow() works correctly
317 SetHWND((WXHWND)hFileDlg);
318
319 if ( m_centreDir )
320 {
321 // now we have the real dialog size, remember it
322 RECT rect;
323 GetWindowRect(hFileDlg, &rect);
324 gs_rectDialog = wxRectFromRECT(rect);
325
326 // and position the window correctly: notice that we must use the base
327 // class version as our own doesn't do anything except setting flags
328 wxFileDialogBase::DoCentre(m_centreDir);
329 }
330 else // need to just move it to the correct place
331 {
332 SetPosition(gs_rectDialog.GetPosition());
333 }
334
335 // Call selection change handler so that update handler will be
336 // called once with no selection.
337 MSWOnSelChange(hDlg);
338
339 // we shouldn't destroy this HWND
340 SetHWND(NULL);
341 }
342
343 void wxFileDialog::MSWOnSelChange(WXHWND hDlg)
344 {
345 TCHAR buf[MAX_PATH];
346 LRESULT len = SendMessage(::GetParent(hDlg), CDM_GETFILEPATH,
347 MAX_PATH, reinterpret_cast<LPARAM>(buf));
348
349 if ( len > 0 )
350 m_currentlySelectedFilename = buf;
351 else
352 m_currentlySelectedFilename.clear();
353
354 if ( m_extraControl )
355 m_extraControl->UpdateWindowUI(wxUPDATE_UI_RECURSE);
356 }
357
358 // helper used below in ShowCommFileDialog(): style is used to determine
359 // whether to show the "Save file" dialog (if it contains wxFD_SAVE bit) or
360 // "Open file" one; returns true on success or false on failure in which case
361 // err is filled with the CDERR_XXX constant
362 static bool DoShowCommFileDialog(OPENFILENAME *of, long style, DWORD *err)
363 {
364 if ( style & wxFD_SAVE ? GetSaveFileName(of) : GetOpenFileName(of) )
365 return true;
366
367 if ( err )
368 {
369 #ifdef __WXWINCE__
370 // according to MSDN, CommDlgExtendedError() should work under CE as
371 // well but apparently in practice it doesn't (anybody has more
372 // details?)
373 *err = GetLastError();
374 #else
375 *err = CommDlgExtendedError();
376 #endif
377 }
378
379 return false;
380 }
381
382 // We want to use OPENFILENAME struct version 5 (Windows 2000/XP) but we don't
383 // know if the OPENFILENAME declared in the currently used headers is a V5 or
384 // V4 (smaller) one so we try to manually extend the struct in case it is the
385 // old one.
386 //
387 // We don't do this on Windows CE nor under Win64, however, as there are no
388 // compilers with old headers for these architectures
389 #if defined(__WXWINCE__) || defined(__WIN64__)
390 typedef OPENFILENAME wxOPENFILENAME;
391
392 static const DWORD gs_ofStructSize = sizeof(OPENFILENAME);
393 #else // !__WXWINCE__ || __WIN64__
394 #define wxTRY_SMALLER_OPENFILENAME
395
396 struct wxOPENFILENAME : public OPENFILENAME
397 {
398 // fields added in Windows 2000/XP comdlg32.dll version
399 void *pVoid;
400 DWORD dw1;
401 DWORD dw2;
402 };
403
404 // hardcoded sizeof(OPENFILENAME) in the Platform SDK: we have to do it
405 // because sizeof(OPENFILENAME) in the headers we use when compiling the
406 // library could be less if _WIN32_WINNT is not >= 0x500
407 static const DWORD wxOPENFILENAME_V5_SIZE = 88;
408
409 // this is hardcoded sizeof(OPENFILENAME_NT4) from Platform SDK
410 static const DWORD wxOPENFILENAME_V4_SIZE = 76;
411
412 // always try the new one first
413 static DWORD gs_ofStructSize = wxOPENFILENAME_V5_SIZE;
414 #endif // __WXWINCE__ || __WIN64__/!...
415
416 static bool ShowCommFileDialog(OPENFILENAME *of, long style)
417 {
418 DWORD errCode;
419 bool success = DoShowCommFileDialog(of, style, &errCode);
420
421 #ifdef wxTRY_SMALLER_OPENFILENAME
422 // the system might be too old to support the new version file dialog
423 // boxes, try with the old size
424 if ( !success && errCode == CDERR_STRUCTSIZE &&
425 of->lStructSize != wxOPENFILENAME_V4_SIZE )
426 {
427 of->lStructSize = wxOPENFILENAME_V4_SIZE;
428
429 success = DoShowCommFileDialog(of, style, &errCode);
430
431 if ( success || !errCode )
432 {
433 // use this struct size for subsequent dialogs
434 gs_ofStructSize = of->lStructSize;
435 }
436 }
437 #endif // wxTRY_SMALLER_OPENFILENAME
438
439 if ( !success &&
440 // FNERR_INVALIDFILENAME is not defined under CE (besides we don't
441 // use CommDlgExtendedError() there anyhow)
442 #ifndef __WXWINCE__
443 errCode == FNERR_INVALIDFILENAME &&
444 #endif // !__WXWINCE__
445 of->lpstrFile[0] )
446 {
447 // this can happen if the default file name is invalid, try without it
448 // now
449 of->lpstrFile[0] = wxT('\0');
450 success = DoShowCommFileDialog(of, style, &errCode);
451 }
452
453 if ( !success )
454 {
455 // common dialog failed - why?
456 if ( errCode != 0 )
457 {
458 wxLogError(_("File dialog failed with error code %0lx."), errCode);
459 }
460 //else: it was just cancelled
461
462 return false;
463 }
464
465 return true;
466 }
467
468 #ifndef __WXWINCE__
469 void wxFileDialog::MSWOnInitDialogHook(WXHWND hwnd)
470 {
471 SetHWND(hwnd);
472
473 CreateExtraControl();
474
475 SetHWND(NULL);
476 }
477 #endif // __WXWINCE__
478
479 int wxFileDialog::ShowModal()
480 {
481 WX_HOOK_MODAL_DIALOG();
482
483 HWND hWnd = 0;
484 if (m_parent) hWnd = (HWND) m_parent->GetHWND();
485 if (!hWnd && wxTheApp->GetTopWindow())
486 hWnd = (HWND) wxTheApp->GetTopWindow()->GetHWND();
487
488 static wxChar fileNameBuffer [ wxMAXPATH ]; // the file-name
489 wxChar titleBuffer [ wxMAXFILE+1+wxMAXEXT ]; // the file-name, without path
490
491 *fileNameBuffer = wxT('\0');
492 *titleBuffer = wxT('\0');
493
494 long msw_flags = OFN_HIDEREADONLY;
495
496 if ( HasFdFlag(wxFD_FILE_MUST_EXIST) )
497 msw_flags |= OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
498 /*
499 If the window has been moved the programmer is probably
500 trying to center or position it. Thus we set the callback
501 or hook function so that we can actually adjust the position.
502 Without moving or centering the dlg, it will just stay
503 in the upper left of the frame, it does not center
504 automatically.
505 */
506 if (m_bMovedWindow || HasExtraControlCreator()) // we need these flags.
507 {
508 ChangeExceptionPolicy();
509 msw_flags |= OFN_EXPLORER|OFN_ENABLEHOOK;
510 #ifndef __WXWINCE__
511 msw_flags |= OFN_ENABLESIZING;
512 #endif
513 }
514
515 wxON_BLOCK_EXIT0(RestoreExceptionPolicy);
516
517 if ( HasFdFlag(wxFD_MULTIPLE) )
518 {
519 // OFN_EXPLORER must always be specified with OFN_ALLOWMULTISELECT
520 msw_flags |= OFN_EXPLORER | OFN_ALLOWMULTISELECT;
521 }
522
523 // if wxFD_CHANGE_DIR flag is not given we shouldn't change the CWD which the
524 // standard dialog does by default (notice that under NT it does it anyhow,
525 // OFN_NOCHANGEDIR or not, see below)
526 if ( !HasFdFlag(wxFD_CHANGE_DIR) )
527 {
528 msw_flags |= OFN_NOCHANGEDIR;
529 }
530
531 if ( HasFdFlag(wxFD_OVERWRITE_PROMPT) )
532 {
533 msw_flags |= OFN_OVERWRITEPROMPT;
534 }
535
536 wxOPENFILENAME of;
537 wxZeroMemory(of);
538
539 of.lStructSize = gs_ofStructSize;
540 of.hwndOwner = hWnd;
541 of.lpstrTitle = m_message.t_str();
542 of.lpstrFileTitle = titleBuffer;
543 of.nMaxFileTitle = wxMAXFILE + 1 + wxMAXEXT;
544
545 #ifndef __WXWINCE__
546 GlobalPtr hgbl;
547 if ( HasExtraControlCreator() )
548 {
549 msw_flags |= OFN_ENABLETEMPLATEHANDLE;
550
551 hgbl.Init(256, GMEM_ZEROINIT);
552 GlobalPtrLock hgblLock(hgbl);
553 LPDLGTEMPLATE lpdt = static_cast<LPDLGTEMPLATE>(hgblLock.Get());
554
555 // Define a dialog box.
556
557 lpdt->style = DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS;
558 lpdt->cdit = 0; // Number of controls
559 lpdt->x = 0;
560 lpdt->y = 0;
561
562 // convert the size of the extra controls to the dialog units
563 const wxSize extraSize = GetExtraControlSize();
564 const LONG baseUnits = ::GetDialogBaseUnits();
565 lpdt->cx = ::MulDiv(extraSize.x, 4, LOWORD(baseUnits));
566 lpdt->cy = ::MulDiv(extraSize.y, 8, HIWORD(baseUnits));
567
568 // after the DLGTEMPLATE there are 3 additional WORDs for dialog menu,
569 // class and title, all three set to zeros.
570
571 of.hInstance = (HINSTANCE)lpdt;
572 }
573 #endif // __WXWINCE__
574
575 // Convert forward slashes to backslashes (file selector doesn't like
576 // forward slashes) and also squeeze multiple consecutive slashes into one
577 // as it doesn't like two backslashes in a row neither
578
579 wxString dir;
580 size_t i, len = m_dir.length();
581 dir.reserve(len);
582 for ( i = 0; i < len; i++ )
583 {
584 wxChar ch = m_dir[i];
585 switch ( ch )
586 {
587 case wxT('/'):
588 // convert to backslash
589 ch = wxT('\\');
590
591 // fall through
592
593 case wxT('\\'):
594 while ( i < len - 1 )
595 {
596 wxChar chNext = m_dir[i + 1];
597 if ( chNext != wxT('\\') && chNext != wxT('/') )
598 break;
599
600 // ignore the next one, unless it is at the start of a UNC path
601 if (i > 0)
602 i++;
603 else
604 break;
605 }
606 // fall through
607
608 default:
609 // normal char
610 dir += ch;
611 }
612 }
613
614 of.lpstrInitialDir = dir.c_str();
615
616 of.Flags = msw_flags;
617 of.lpfnHook = wxFileDialogHookFunction;
618 of.lCustData = (LPARAM)this;
619
620 wxArrayString wildDescriptions, wildFilters;
621
622 size_t items = wxParseCommonDialogsFilter(m_wildCard, wildDescriptions, wildFilters);
623
624 wxASSERT_MSG( items > 0 , wxT("empty wildcard list") );
625
626 wxString filterBuffer;
627
628 for (i = 0; i < items ; i++)
629 {
630 filterBuffer += wildDescriptions[i];
631 filterBuffer += wxT("|");
632 filterBuffer += wildFilters[i];
633 filterBuffer += wxT("|");
634 }
635
636 // Replace | with \0
637 for (i = 0; i < filterBuffer.length(); i++ ) {
638 if ( filterBuffer.GetChar(i) == wxT('|') ) {
639 filterBuffer[i] = wxT('\0');
640 }
641 }
642
643 of.lpstrFilter = filterBuffer.t_str();
644 of.nFilterIndex = m_filterIndex + 1;
645
646 //=== Setting defaultFileName >>=========================================
647
648 wxStrlcpy(fileNameBuffer, m_fileName.c_str(), WXSIZEOF(fileNameBuffer));
649
650 of.lpstrFile = fileNameBuffer; // holds returned filename
651 of.nMaxFile = wxMAXPATH;
652
653 // we must set the default extension because otherwise Windows would check
654 // for the existing of a wrong file with wxFD_OVERWRITE_PROMPT (i.e. if the
655 // user types "foo" and the default extension is ".bar" we should force it
656 // to check for "foo.bar" existence and not "foo")
657 wxString defextBuffer; // we need it to be alive until GetSaveFileName()!
658 if (HasFdFlag(wxFD_SAVE))
659 {
660 const wxChar* extension = filterBuffer.t_str();
661 int maxFilter = (int)(of.nFilterIndex*2L) - 1;
662
663 for( int i = 0; i < maxFilter; i++ ) // get extension
664 extension = extension + wxStrlen( extension ) + 1;
665
666 // use dummy name a to avoid assert in AppendExtension
667 defextBuffer = AppendExtension(wxT("a"), extension);
668 if (defextBuffer.StartsWith(wxT("a.")))
669 {
670 defextBuffer = defextBuffer.Mid(2); // remove "a."
671 of.lpstrDefExt = defextBuffer.c_str();
672 }
673 }
674
675 // store off before the standard windows dialog can possibly change it
676 const wxString cwdOrig = wxGetCwd();
677
678 //== Execute FileDialog >>=================================================
679
680 if ( !ShowCommFileDialog(&of, m_windowStyle) )
681 return wxID_CANCEL;
682
683 // GetOpenFileName will always change the current working directory on
684 // (according to MSDN) "Windows NT 4.0/2000/XP" because the flag
685 // OFN_NOCHANGEDIR has no effect. If the user did not specify
686 // wxFD_CHANGE_DIR let's restore the current working directory to what it
687 // was before the dialog was shown.
688 if ( msw_flags & OFN_NOCHANGEDIR )
689 {
690 wxSetWorkingDirectory(cwdOrig);
691 }
692
693 m_fileNames.Empty();
694
695 if ( ( HasFdFlag(wxFD_MULTIPLE) ) &&
696 #if defined(OFN_EXPLORER)
697 ( fileNameBuffer[of.nFileOffset-1] == wxT('\0') )
698 #else
699 ( fileNameBuffer[of.nFileOffset-1] == wxT(' ') )
700 #endif // OFN_EXPLORER
701 )
702 {
703 #if defined(OFN_EXPLORER)
704 m_dir = fileNameBuffer;
705 i = of.nFileOffset;
706 m_fileName = &fileNameBuffer[i];
707 m_fileNames.Add(m_fileName);
708 i += m_fileName.length() + 1;
709
710 while (fileNameBuffer[i] != wxT('\0'))
711 {
712 m_fileNames.Add(&fileNameBuffer[i]);
713 i += wxStrlen(&fileNameBuffer[i]) + 1;
714 }
715 #else
716 wxStringTokenizer toke(fileNameBuffer, wxT(" \t\r\n"));
717 m_dir = toke.GetNextToken();
718 m_fileName = toke.GetNextToken();
719 m_fileNames.Add(m_fileName);
720
721 while (toke.HasMoreTokens())
722 m_fileNames.Add(toke.GetNextToken());
723 #endif // OFN_EXPLORER
724
725 wxString dir(m_dir);
726 if ( m_dir.Last() != wxT('\\') )
727 dir += wxT('\\');
728
729 m_path = dir + m_fileName;
730 m_filterIndex = (int)of.nFilterIndex - 1;
731 }
732 else
733 {
734 //=== Adding the correct extension >>=================================
735
736 m_filterIndex = (int)of.nFilterIndex - 1;
737
738 if ( !of.nFileExtension ||
739 (of.nFileExtension && fileNameBuffer[of.nFileExtension] == wxT('\0')) )
740 {
741 // User has typed a filename without an extension:
742 const wxChar* extension = filterBuffer.t_str();
743 int maxFilter = (int)(of.nFilterIndex*2L) - 1;
744
745 for( int i = 0; i < maxFilter; i++ ) // get extension
746 extension = extension + wxStrlen( extension ) + 1;
747
748 m_fileName = AppendExtension(fileNameBuffer, extension);
749 wxStrlcpy(fileNameBuffer, m_fileName.c_str(), WXSIZEOF(fileNameBuffer));
750 }
751
752 m_path = fileNameBuffer;
753 m_fileName = wxFileNameFromPath(fileNameBuffer);
754 m_fileNames.Add(m_fileName);
755 m_dir = wxPathOnly(fileNameBuffer);
756 }
757
758 return wxID_OK;
759
760 }
761
762 #endif // wxUSE_FILEDLG && !(__SMARTPHONE__ && __WXWINCE__)