]> git.saurik.com Git - wxWidgets.git/blame - src/msw/filedlg.cpp
Fix pulsing of bitmaps in focused buttons under Windows 7.
[wxWidgets.git] / src / msw / filedlg.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////////
f6bcfd97 2// Name: src/msw/filedlg.cpp
2bda0e17
KB
3// Purpose: wxFileDialog
4// Author: Julian Smart
5// Modified by:
6// Created: 01/02/97
7// RCS-ID: $Id$
6c9a19aa 8// Copyright: (c) Julian Smart
65571936 9// Licence: wxWindows licence
2bda0e17
KB
10/////////////////////////////////////////////////////////////////////////////
11
f6bcfd97
BP
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
2bda0e17
KB
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
ba681060 24 #pragma hdrstop
2bda0e17
KB
25#endif
26
3180bc0e 27#if wxUSE_FILEDLG && !(defined(__SMARTPHONE__) && defined(__WXWINCE__))
1e6feb95 28
949c9f74
WS
29#include "wx/filedlg.h"
30
2bda0e17 31#ifndef WX_PRECOMP
57bd4c60
WS
32 #include "wx/msw/wrapcdlg.h"
33 #include "wx/msw/missing.h"
ba681060
VZ
34 #include "wx/utils.h"
35 #include "wx/msgdlg.h"
2b5f62a0 36 #include "wx/filefn.h"
ba681060 37 #include "wx/intl.h"
2662e49e 38 #include "wx/log.h"
f6bcfd97 39 #include "wx/app.h"
18680f86 40 #include "wx/math.h"
8f177c8e 41#endif
2bda0e17 42
2bda0e17
KB
43#include <stdlib.h>
44#include <string.h>
45
30374272 46#include "wx/dynlib.h"
8ad9ca97 47#include "wx/filename.h"
30374272 48#include "wx/scopeguard.h"
8f177c8e 49#include "wx/tokenzr.h"
643e9cf9 50#include "wx/testing.h"
8f177c8e 51
f6bcfd97
BP
52// ----------------------------------------------------------------------------
53// constants
54// ----------------------------------------------------------------------------
55
56#ifdef __WIN32__
2b5f62a0 57# define wxMAXPATH 65534
f6bcfd97
BP
58#else
59# define wxMAXPATH 1024
60#endif
61
62# define wxMAXFILE 1024
63
64# define wxMAXEXT 5
65
0b11099d
VZ
66// ----------------------------------------------------------------------------
67// globals
68// ----------------------------------------------------------------------------
69
0a7b0229 70// standard dialog size for the old Windows systems where the dialog wasn't
d13b34d3 71// resizable
0b11099d
VZ
72static wxRect gs_rectDialog(0, 0, 428, 266);
73
f6bcfd97
BP
74// ============================================================================
75// implementation
76// ============================================================================
77
f74172ab 78IMPLEMENT_CLASS(wxFileDialog, wxFileDialogBase)
2bda0e17 79
30374272
DS
80// ----------------------------------------------------------------------------
81
82namespace
83{
84
85#if wxUSE_DYNLIB_CLASS
86
87typedef BOOL (WINAPI *GetProcessUserModeExceptionPolicy_t)(LPDWORD);
88typedef BOOL (WINAPI *SetProcessUserModeExceptionPolicy_t)(DWORD);
89
90GetProcessUserModeExceptionPolicy_t gs_pfnGetProcessUserModeExceptionPolicy
91 = (GetProcessUserModeExceptionPolicy_t) -1;
92
93SetProcessUserModeExceptionPolicy_t gs_pfnSetProcessUserModeExceptionPolicy
94 = (SetProcessUserModeExceptionPolicy_t) -1;
95
96DWORD gs_oldExceptionPolicyFlags = 0;
97
98bool gs_changedPolicy = false;
99
100#endif // #if wxUSE_DYNLIB_CLASS
101
102/*
103Since Windows 7 by default (callback) exceptions aren't swallowed anymore
104with native x64 applications. Exceptions can occur in a file dialog when
105using the hook procedure in combination with third-party utilities.
106Since Windows 7 SP1 the swallowing of exceptions can be enabled again
107by using SetProcessUserModeExceptionPolicy.
108*/
109void 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
139void 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
0b11099d
VZ
152// ----------------------------------------------------------------------------
153// hook function for moving the dialog
154// ----------------------------------------------------------------------------
155
106d80ad 156UINT_PTR APIENTRY
0b11099d
VZ
157wxFileDialogHookFunction(HWND hDlg,
158 UINT iMsg,
159 WPARAM WXUNUSED(wParam),
160 LPARAM lParam)
161{
cb80db46 162 switch ( iMsg )
0b11099d 163 {
d6dae1b4 164#ifndef __WXWINCE__
6fa6d659
VZ
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;
d6dae1b4 172#endif // __WXWINCE__
6fa6d659 173
0b11099d
VZ
174 case WM_NOTIFY:
175 {
5c33522f 176 OFNOTIFY *pNotifyCode = reinterpret_cast<OFNOTIFY *>(lParam);
cb80db46 177 if ( pNotifyCode->hdr.code == CDN_INITDONE )
0b11099d 178 {
5c33522f 179 reinterpret_cast<wxFileDialog *>(
0a7b0229
VZ
180 pNotifyCode->lpOFN->lCustData)
181 ->MSWOnInitDone((WXHWND)hDlg);
0b11099d
VZ
182 }
183 }
184 break;
cb80db46
VZ
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;
0b11099d
VZ
194 }
195
196 // do the default processing
197 return 0;
198}
199
f6bcfd97 200// ----------------------------------------------------------------------------
b600ed13 201// wxFileDialog
f6bcfd97
BP
202// ----------------------------------------------------------------------------
203
2b5f62a0
VZ
204wxFileDialog::wxFileDialog(wxWindow *parent,
205 const wxString& message,
206 const wxString& defaultDir,
207 const wxString& defaultFileName,
208 const wxString& wildCard,
209 long style,
ff3e84ff
VZ
210 const wxPoint& pos,
211 const wxSize& sz,
212 const wxString& name)
0b11099d 213 : wxFileDialogBase(parent, message, defaultDir, defaultFileName,
ff3e84ff 214 wildCard, style, pos, sz, name)
f74172ab 215
2bda0e17 216{
556151f5 217 // NB: all style checks are done by wxFileDialogBase::Create
2bda0e17 218
0b11099d 219 m_bMovedWindow = false;
0a7b0229 220 m_centreDir = 0;
0b11099d
VZ
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;
0b11099d 227}
0a7b0229 228
c61f4f6d
VZ
229void wxFileDialog::GetPaths(wxArrayString& paths) const
230{
231 paths.Empty();
232
233 wxString dir(m_dir);
b39badac 234 if ( m_dir.empty() || m_dir.Last() != wxT('\\') )
9a83f860 235 dir += wxT('\\');
c61f4f6d
VZ
236
237 size_t count = m_fileNames.GetCount();
238 for ( size_t n = 0; n < count; n++ )
239 {
8ad9ca97
JS
240 if (wxFileName(m_fileNames[n]).IsAbsolute())
241 paths.Add(m_fileNames[n]);
242 else
243 paths.Add(dir + m_fileNames[n]);
c61f4f6d
VZ
244 }
245}
246
89654c9a
VZ
247void wxFileDialog::GetFilenames(wxArrayString& files) const
248{
249 files = m_fileNames;
250}
251
cb80db46 252void wxFileDialog::DoGetPosition(int *x, int *y) const
0b11099d 253{
cb80db46
VZ
254 if ( x )
255 *x = gs_rectDialog.x;
256 if ( y )
257 *y = gs_rectDialog.y;
0b11099d
VZ
258}
259
0b11099d
VZ
260void wxFileDialog::DoGetSize(int *width, int *height) const
261{
cb80db46
VZ
262 if ( width )
263 *width = gs_rectDialog.width;
264 if ( height )
265 *height = gs_rectDialog.height;
0b11099d
VZ
266}
267
cb80db46 268void wxFileDialog::DoMoveWindow(int x, int y, int WXUNUSED(w), int WXUNUSED(h))
0b11099d 269{
0b11099d
VZ
270 gs_rectDialog.x = x;
271 gs_rectDialog.y = y;
272
0a7b0229
VZ
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
292void 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
301void wxFileDialog::MSWOnInitDone(WXHWND hDlg)
302{
4c51a665 303 // note the dialog is the parent window: hDlg is a child of it when
0a7b0229
VZ
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);
0b11099d
VZ
328}
329
fe048d77
VZ
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
c46c1fb8
VZ
334static bool DoShowCommFileDialog(OPENFILENAME *of, long style, DWORD *err)
335{
e031f1df 336 if ( style & wxFD_SAVE ? GetSaveFileName(of) : GetOpenFileName(of) )
c46c1fb8
VZ
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
04227efc
VZ
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.
5bb37216 358//
04227efc
VZ
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__)
5bb37216
VZ
362 typedef OPENFILENAME wxOPENFILENAME;
363
04227efc
VZ
364 static const DWORD gs_ofStructSize = sizeof(OPENFILENAME);
365#else // !__WXWINCE__ || __WIN64__
366 #define wxTRY_SMALLER_OPENFILENAME
367
5bb37216
VZ
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;
5bb37216 383
04227efc
VZ
384 // always try the new one first
385 static DWORD gs_ofStructSize = wxOPENFILENAME_V5_SIZE;
386#endif // __WXWINCE__ || __WIN64__/!...
5bb37216 387
fe048d77
VZ
388static 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
d4380371
VZ
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] )
fe048d77
VZ
418 {
419 // this can happen if the default file name is invalid, try without it
420 // now
9a83f860 421 of->lpstrFile[0] = wxT('\0');
fe048d77
VZ
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
d6dae1b4 440#ifndef __WXWINCE__
6fa6d659
VZ
441void wxFileDialog::MSWOnInitDialogHook(WXHWND hwnd)
442{
443 SetHWND(hwnd);
444
445 CreateExtraControl();
446
447 SetHWND(NULL);
448}
d6dae1b4 449#endif // __WXWINCE__
6fa6d659 450
c61f4f6d 451int wxFileDialog::ShowModal()
2bda0e17 452{
643e9cf9
VS
453 WX_TESTING_SHOW_MODAL_HOOK();
454
1f2f0331
VZ
455 HWND hWnd = 0;
456 if (m_parent) hWnd = (HWND) m_parent->GetHWND();
f6bcfd97
BP
457 if (!hWnd && wxTheApp->GetTopWindow())
458 hWnd = (HWND) wxTheApp->GetTopWindow()->GetHWND();
2bda0e17 459
f6bcfd97
BP
460 static wxChar fileNameBuffer [ wxMAXPATH ]; // the file-name
461 wxChar titleBuffer [ wxMAXFILE+1+wxMAXEXT ]; // the file-name, without path
2bda0e17 462
223d09f6
KB
463 *fileNameBuffer = wxT('\0');
464 *titleBuffer = wxT('\0');
2bda0e17 465
21416306 466 long msw_flags = OFN_HIDEREADONLY;
21416306 467
b014db05 468 if ( HasFdFlag(wxFD_FILE_MUST_EXIST) )
1f2f0331 469 msw_flags |= OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
0b11099d
VZ
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
5bb37216 476 automatically.
0b11099d 477 */
6fa6d659 478 if (m_bMovedWindow || HasExtraControlCreator()) // we need these flags.
503528dc 479 {
30374272 480 ChangeExceptionPolicy();
503528dc
JS
481 msw_flags |= OFN_EXPLORER|OFN_ENABLEHOOK;
482#ifndef __WXWINCE__
483 msw_flags |= OFN_ENABLESIZING;
484#endif
485 }
6e8aa701 486
30374272
DS
487 wxON_BLOCK_EXIT0(RestoreExceptionPolicy);
488
b014db05 489 if ( HasFdFlag(wxFD_MULTIPLE) )
6e8aa701
VZ
490 {
491 // OFN_EXPLORER must always be specified with OFN_ALLOWMULTISELECT
492 msw_flags |= OFN_EXPLORER | OFN_ALLOWMULTISELECT;
493 }
494
e031f1df 495 // if wxFD_CHANGE_DIR flag is not given we shouldn't change the CWD which the
af1f0a76
VZ
496 // standard dialog does by default (notice that under NT it does it anyhow,
497 // OFN_NOCHANGEDIR or not, see below)
b014db05 498 if ( !HasFdFlag(wxFD_CHANGE_DIR) )
6e8aa701
VZ
499 {
500 msw_flags |= OFN_NOCHANGEDIR;
501 }
ac95e671 502
b014db05 503 if ( HasFdFlag(wxFD_OVERWRITE_PROMPT) )
99d1b93d
VZ
504 {
505 msw_flags |= OFN_OVERWRITEPROMPT;
506 }
ac95e671 507
5bb37216 508 wxOPENFILENAME of;
f6bcfd97
BP
509 wxZeroMemory(of);
510
5bb37216 511 of.lStructSize = gs_ofStructSize;
e15e548b 512 of.hwndOwner = hWnd;
017dc06b 513 of.lpstrTitle = m_message.t_str();
e15e548b 514 of.lpstrFileTitle = titleBuffer;
5bb37216 515 of.nMaxFileTitle = wxMAXFILE + 1 + wxMAXEXT;
2bda0e17 516
6fa6d659
VZ
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
c10c791b
VZ
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));
6fa6d659
VZ
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
0bc9b25e 547 // Convert forward slashes to backslashes (file selector doesn't like
99d1b93d
VZ
548 // forward slashes) and also squeeze multiple consecutive slashes into one
549 // as it doesn't like two backslashes in a row neither
0627d091 550
cbe874bd
WS
551 wxString dir;
552 size_t i, len = m_dir.length();
99d1b93d 553 dir.reserve(len);
0627d091 554 for ( i = 0; i < len; i++ )
99d1b93d
VZ
555 {
556 wxChar ch = m_dir[i];
557 switch ( ch )
558 {
9a83f860 559 case wxT('/'):
99d1b93d 560 // convert to backslash
9a83f860 561 ch = wxT('\\');
99d1b93d
VZ
562
563 // fall through
0bc9b25e 564
9a83f860 565 case wxT('\\'):
99d1b93d
VZ
566 while ( i < len - 1 )
567 {
568 wxChar chNext = m_dir[i + 1];
9a83f860 569 if ( chNext != wxT('\\') && chNext != wxT('/') )
99d1b93d
VZ
570 break;
571
04d93c3a
CE
572 // ignore the next one, unless it is at the start of a UNC path
573 if (i > 0)
574 i++;
575 else
0b11099d 576 break;
99d1b93d
VZ
577 }
578 // fall through
579
580 default:
581 // normal char
582 dir += ch;
583 }
584 }
585
586 of.lpstrInitialDir = dir.c_str();
2bda0e17 587
e15e548b 588 of.Flags = msw_flags;
0b11099d 589 of.lpfnHook = wxFileDialogHookFunction;
0a7b0229 590 of.lCustData = (LPARAM)this;
2bda0e17 591
daf32463 592 wxArrayString wildDescriptions, wildFilters;
2bda0e17 593
daf32463 594 size_t items = wxParseCommonDialogsFilter(m_wildCard, wildDescriptions, wildFilters);
2bda0e17 595
9a83f860 596 wxASSERT_MSG( items > 0 , wxT("empty wildcard list") );
2bda0e17 597
1f2f0331 598 wxString filterBuffer;
2bda0e17 599
daf32463
WS
600 for (i = 0; i < items ; i++)
601 {
602 filterBuffer += wildDescriptions[i];
603 filterBuffer += wxT("|");
604 filterBuffer += wildFilters[i];
605 filterBuffer += wxT("|");
574c0bbf
JS
606 }
607
574c0bbf 608 // Replace | with \0
e031f1df 609 for (i = 0; i < filterBuffer.length(); i++ ) {
223d09f6
KB
610 if ( filterBuffer.GetChar(i) == wxT('|') ) {
611 filterBuffer[i] = wxT('\0');
e15e548b
VZ
612 }
613 }
2bda0e17 614
017dc06b 615 of.lpstrFilter = filterBuffer.t_str();
cc42eb7a 616 of.nFilterIndex = m_filterIndex + 1;
2bda0e17
KB
617
618 //=== Setting defaultFileName >>=========================================
619
64accea5 620 wxStrlcpy(fileNameBuffer, m_fileName.c_str(), WXSIZEOF(fileNameBuffer));
2bda0e17 621
e15e548b 622 of.lpstrFile = fileNameBuffer; // holds returned filename
f6bcfd97 623 of.nMaxFile = wxMAXPATH;
2bda0e17 624
90bddb85 625 // we must set the default extension because otherwise Windows would check
e031f1df 626 // for the existing of a wrong file with wxFD_OVERWRITE_PROMPT (i.e. if the
90bddb85
VZ
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()!
b014db05 630 if (HasFdFlag(wxFD_SAVE))
90bddb85 631 {
017dc06b 632 const wxChar* extension = filterBuffer.t_str();
90bddb85
VZ
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 {
026ff75b 642 defextBuffer = defextBuffer.Mid(2); // remove "a."
90bddb85
VZ
643 of.lpstrDefExt = defextBuffer.c_str();
644 }
645 }
0b11099d 646
af1f0a76
VZ
647 // store off before the standard windows dialog can possibly change it
648 const wxString cwdOrig = wxGetCwd();
649
2bda0e17
KB
650 //== Execute FileDialog >>=================================================
651
fe048d77
VZ
652 if ( !ShowCommFileDialog(&of, m_windowStyle) )
653 return wxID_CANCEL;
2bda0e17 654
fe048d77
VZ
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 )
f6bcfd97 661 {
fe048d77 662 wxSetWorkingDirectory(cwdOrig);
f6bcfd97 663 }
c46c1fb8 664
fe048d77 665 m_fileNames.Empty();
c61f4f6d 666
fe048d77 667 if ( ( HasFdFlag(wxFD_MULTIPLE) ) &&
c61f4f6d 668#if defined(OFN_EXPLORER)
fe048d77 669 ( fileNameBuffer[of.nFileOffset-1] == wxT('\0') )
c61f4f6d 670#else
fe048d77 671 ( fileNameBuffer[of.nFileOffset-1] == wxT(' ') )
c61f4f6d 672#endif // OFN_EXPLORER
fe048d77
VZ
673 )
674 {
c61f4f6d 675#if defined(OFN_EXPLORER)
fe048d77
VZ
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;
c61f4f6d 681
fe048d77
VZ
682 while (fileNameBuffer[i] != wxT('\0'))
683 {
684 m_fileNames.Add(&fileNameBuffer[i]);
685 i += wxStrlen(&fileNameBuffer[i]) + 1;
686 }
c61f4f6d 687#else
9a83f860 688 wxStringTokenizer toke(fileNameBuffer, wxT(" \t\r\n"));
fe048d77
VZ
689 m_dir = toke.GetNextToken();
690 m_fileName = toke.GetNextToken();
691 m_fileNames.Add(m_fileName);
c61f4f6d 692
fe048d77
VZ
693 while (toke.HasMoreTokens())
694 m_fileNames.Add(toke.GetNextToken());
c61f4f6d
VZ
695#endif // OFN_EXPLORER
696
fe048d77 697 wxString dir(m_dir);
9a83f860
VZ
698 if ( m_dir.Last() != wxT('\\') )
699 dir += wxT('\\');
2bda0e17 700
fe048d77
VZ
701 m_path = dir + m_fileName;
702 m_filterIndex = (int)of.nFilterIndex - 1;
703 }
704 else
705 {
706 //=== Adding the correct extension >>=================================
2bda0e17 707
fe048d77 708 m_filterIndex = (int)of.nFilterIndex - 1;
2bda0e17 709
fe048d77
VZ
710 if ( !of.nFileExtension ||
711 (of.nFileExtension && fileNameBuffer[of.nFileExtension] == wxT('\0')) )
712 {
713 // User has typed a filename without an extension:
017dc06b 714 const wxChar* extension = filterBuffer.t_str();
fe048d77 715 int maxFilter = (int)(of.nFilterIndex*2L) - 1;
a039ccbf 716
fe048d77
VZ
717 for( int i = 0; i < maxFilter; i++ ) // get extension
718 extension = extension + wxStrlen( extension ) + 1;
2bda0e17 719
fe048d77 720 m_fileName = AppendExtension(fileNameBuffer, extension);
e408bf52 721 wxStrlcpy(fileNameBuffer, m_fileName.c_str(), WXSIZEOF(fileNameBuffer));
c61f4f6d 722 }
fe048d77
VZ
723
724 m_path = fileNameBuffer;
725 m_fileName = wxFileNameFromPath(fileNameBuffer);
726 m_fileNames.Add(m_fileName);
727 m_dir = wxPathOnly(fileNameBuffer);
7cc98b3e 728 }
2bda0e17 729
fe048d77 730 return wxID_OK;
2bda0e17
KB
731
732}
733
3180bc0e 734#endif // wxUSE_FILEDLG && !(__SMARTPHONE__ && __WXWINCE__)