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