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