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