]> git.saurik.com Git - wxWidgets.git/blame - src/msw/stdpaths.cpp
Don't overwrite status message when restoring it if it changed.
[wxWidgets.git] / src / msw / stdpaths.cpp
CommitLineData
40e8ee37
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: msw/stdpaths.cpp
3// Purpose: wxStandardPaths implementation for Win32
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 2004-10-19
7// RCS-ID: $Id$
8// Copyright: (c) 2004 Vadim Zeitlin <vadim@wxwindows.org>
9// License: wxWindows license
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
cd9a8d40
VZ
27#if wxUSE_STDPATHS
28
de303444
MW
29#include "wx/stdpaths.h"
30
40e8ee37 31#ifndef WX_PRECOMP
de303444 32 #include "wx/utils.h"
40e8ee37
VZ
33#endif //WX_PRECOMP
34
35#include "wx/dynlib.h"
36#include "wx/filename.h"
37
40e8ee37
VZ
38#include "wx/msw/private.h"
39#include "wx/msw/wrapshl.h"
40
41// ----------------------------------------------------------------------------
42// types
43// ----------------------------------------------------------------------------
44
45typedef HRESULT (WINAPI *SHGetFolderPath_t)(HWND, int, HANDLE, DWORD, LPTSTR);
46typedef HRESULT (WINAPI *SHGetSpecialFolderPath_t)(HWND, LPTSTR, int, BOOL);
47
48// ----------------------------------------------------------------------------
49// constants
50// ----------------------------------------------------------------------------
51
52// used in our wxLogTrace messages
9a83f860 53#define TRACE_MASK wxT("stdpaths")
40e8ee37 54
61c2afed
WS
55#ifndef CSIDL_APPDATA
56 #define CSIDL_APPDATA 0x001a
57#endif
58
40e8ee37
VZ
59#ifndef CSIDL_LOCAL_APPDATA
60 #define CSIDL_LOCAL_APPDATA 0x001c
61#endif
62
63#ifndef CSIDL_COMMON_APPDATA
64 #define CSIDL_COMMON_APPDATA 0x0023
65#endif
66
67#ifndef CSIDL_PROGRAM_FILES
68 #define CSIDL_PROGRAM_FILES 0x0026
69#endif
70
17af82fb
VZ
71#ifndef CSIDL_PERSONAL
72 #define CSIDL_PERSONAL 0x0005
73#endif
74
cd0c4800
WS
75#ifndef SHGFP_TYPE_CURRENT
76 #define SHGFP_TYPE_CURRENT 0
77#endif
78
79#ifndef SHGFP_TYPE_DEFAULT
80 #define SHGFP_TYPE_DEFAULT 1
81#endif
4cd15b49 82
40e8ee37
VZ
83// ----------------------------------------------------------------------------
84// module globals
85// ----------------------------------------------------------------------------
86
4cd15b49
VZ
87namespace
88{
89
40e8ee37
VZ
90struct ShellFunctions
91{
92 ShellFunctions()
93 {
94 pSHGetFolderPath = NULL;
95 pSHGetSpecialFolderPath = NULL;
96 initialized = false;
97 }
98
99 SHGetFolderPath_t pSHGetFolderPath;
100 SHGetSpecialFolderPath_t pSHGetSpecialFolderPath;
101
102 bool initialized;
103};
104
105// in spite of using a static variable, this is MT-safe as in the worst case it
106// results in initializing the function pointer several times -- but this is
107// harmless
4cd15b49 108ShellFunctions gs_shellFuncs;
40e8ee37
VZ
109
110// ----------------------------------------------------------------------------
111// private functions
112// ----------------------------------------------------------------------------
113
4cd15b49 114void ResolveShellFunctions()
40e8ee37 115{
64c288fa
JS
116#if wxUSE_DYNLIB_CLASS
117
40e8ee37 118 // start with the newest functions, fall back to the oldest ones
780d7317 119#ifdef __WXWINCE__
9a83f860 120 wxString shellDllName(wxT("coredll"));
780d7317 121#else
40e8ee37 122 // first check for SHGetFolderPath (shell32.dll 5.0)
9a83f860 123 wxString shellDllName(wxT("shell32"));
780d7317
JS
124#endif
125
126 wxDynamicLibrary dllShellFunctions( shellDllName );
127 if ( !dllShellFunctions.IsLoaded() )
40e8ee37 128 {
9a83f860 129 wxLogTrace(TRACE_MASK, wxT("Failed to load %s.dll"), shellDllName.c_str() );
40e8ee37
VZ
130 }
131
780d7317
JS
132 // don't give errors if the functions are unavailable, we're ready to deal
133 // with this
134 wxLogNull noLog;
135
40e8ee37 136#if wxUSE_UNICODE
780d7317
JS
137 #ifdef __WXWINCE__
138 static const wchar_t UNICODE_SUFFIX = L''; // WinCE SH functions don't seem to have 'W'
139 #else
140 static const wchar_t UNICODE_SUFFIX = L'W';
141 #endif
40e8ee37
VZ
142#else // !Unicode
143 static const char UNICODE_SUFFIX = 'A';
144#endif // Unicode/!Unicode
145
9a83f860 146 wxString funcname(wxT("SHGetFolderPath"));
40e8ee37 147 gs_shellFuncs.pSHGetFolderPath =
780d7317 148 (SHGetFolderPath_t)dllShellFunctions.GetSymbol(funcname + UNICODE_SUFFIX);
40e8ee37
VZ
149
150 // then for SHGetSpecialFolderPath (shell32.dll 4.71)
151 if ( !gs_shellFuncs.pSHGetFolderPath )
152 {
9a83f860 153 funcname = wxT("SHGetSpecialFolderPath");
40e8ee37 154 gs_shellFuncs.pSHGetSpecialFolderPath = (SHGetSpecialFolderPath_t)
780d7317 155 dllShellFunctions.GetSymbol(funcname + UNICODE_SUFFIX);
40e8ee37
VZ
156 }
157
158 // finally we fall back on SHGetSpecialFolderLocation (shell32.dll 4.0),
159 // but we don't need to test for it -- it is available even under Win95
160
161 // shell32.dll is going to be unloaded, but it still remains in memory
162 // because we also link to it statically, so it's ok
163
164 gs_shellFuncs.initialized = true;
64c288fa 165#endif
40e8ee37
VZ
166}
167
4cd15b49
VZ
168} // anonymous namespace
169
40e8ee37
VZ
170// ============================================================================
171// wxStandardPaths implementation
172// ============================================================================
173
174// ----------------------------------------------------------------------------
175// private helpers
176// ----------------------------------------------------------------------------
177
178/* static */
179wxString wxStandardPaths::DoGetDirectory(int csidl)
180{
181 if ( !gs_shellFuncs.initialized )
182 ResolveShellFunctions();
183
184 wxString dir;
185 HRESULT hr = E_FAIL;
186
187 // test whether the function is available during compile-time (it must be
188 // defined as either "SHGetFolderPathA" or "SHGetFolderPathW")
189#ifdef SHGetFolderPath
190 // and now test whether we have it during run-time
191 if ( gs_shellFuncs.pSHGetFolderPath )
192 {
193 hr = gs_shellFuncs.pSHGetFolderPath
194 (
195 NULL, // parent window, not used
196 csidl,
197 NULL, // access token (current user)
198 SHGFP_TYPE_CURRENT, // current path, not just default value
199 wxStringBuffer(dir, MAX_PATH)
200 );
201
202 // somewhat incredibly, the error code in the Unicode version is
203 // different from the one in ASCII version for this function
204#if wxUSE_UNICODE
205 if ( hr == E_FAIL )
206#else
207 if ( hr == S_FALSE )
208#endif
209 {
210 // directory doesn't exist, maybe we can get its default value?
211 hr = gs_shellFuncs.pSHGetFolderPath
212 (
213 NULL,
214 csidl,
215 NULL,
216 SHGFP_TYPE_DEFAULT,
217 wxStringBuffer(dir, MAX_PATH)
218 );
219 }
220 }
221#endif // SHGetFolderPath
222
223#ifdef SHGetSpecialFolderPath
224 if ( FAILED(hr) && gs_shellFuncs.pSHGetSpecialFolderPath )
225 {
226 hr = gs_shellFuncs.pSHGetSpecialFolderPath
227 (
228 NULL, // parent window
229 wxStringBuffer(dir, MAX_PATH),
230 csidl,
231 FALSE // don't create if doesn't exist
232 );
233 }
234#endif // SHGetSpecialFolderPath
235
236 // SHGetSpecialFolderLocation should be available with all compilers and
237 // under all Win32 systems, so don't test for it (and as it doesn't exist
238 // in "A" and "W" versions anyhow, testing would be more involved, too)
239 if ( FAILED(hr) )
240 {
241 LPITEMIDLIST pidl;
242 hr = SHGetSpecialFolderLocation(NULL, csidl, &pidl);
243
244 if ( SUCCEEDED(hr) )
245 {
246 // creating this temp object has (nice) side effect of freeing pidl
247 dir = wxItemIdList(pidl).GetPath();
248 }
249 }
250
251 return dir;
252}
253
4cd15b49 254wxString wxStandardPaths::GetAppDir() const
adaa49a8 255{
4cd15b49 256 if ( m_appDir.empty() )
adaa49a8 257 {
4cd15b49 258 m_appDir = wxFileName(wxGetFullModuleName()).GetPath();
adaa49a8 259 }
adaa49a8 260
4cd15b49 261 return m_appDir;
adaa49a8
VZ
262}
263
17af82fb
VZ
264wxString wxStandardPaths::GetDocumentsDir() const
265{
266 return DoGetDirectory(CSIDL_PERSONAL);
267}
268
4cd15b49
VZ
269// ----------------------------------------------------------------------------
270// MSW-specific functions
271// ----------------------------------------------------------------------------
272
273void wxStandardPaths::IgnoreAppSubDir(const wxString& subdirPattern)
274{
275 wxFileName fn = wxFileName::DirName(GetAppDir());
276
277 if ( !fn.GetDirCount() )
278 {
279 // no last directory to ignore anyhow
280 return;
281 }
282
283 const wxString lastdir = fn.GetDirs().Last().Lower();
284 if ( lastdir.Matches(subdirPattern.Lower()) )
285 {
286 fn.RemoveLastDir();
287
288 // store the cached value so that subsequent calls to GetAppDir() will
289 // reuse it instead of using just the program binary directory
290 m_appDir = fn.GetPath();
291 }
292}
293
294void wxStandardPaths::IgnoreAppBuildSubDirs()
295{
296 IgnoreAppSubDir("debug");
297 IgnoreAppSubDir("release");
298
299 wxString compilerPrefix;
300#ifdef __VISUALC__
301 compilerPrefix = "vc";
302#elif defined(__GNUG__)
303 compilerPrefix = "gcc";
304#elif defined(__BORLANDC__)
305 compilerPrefix = "bcc";
306#elif defined(__DIGITALMARS__)
307 compilerPrefix = "dmc";
308#elif defined(__WATCOMC__)
309 compilerPrefix = "wat";
310#else
311 return;
312#endif
313
314 IgnoreAppSubDir(compilerPrefix + "_msw*");
315}
316
317void wxStandardPaths::DontIgnoreAppSubDir()
318{
319 // this will force the next call to GetAppDir() to use the program binary
320 // path as the application directory
321 m_appDir.clear();
322}
323
40e8ee37
VZ
324// ----------------------------------------------------------------------------
325// public functions
326// ----------------------------------------------------------------------------
327
4cd15b49
VZ
328wxStandardPaths::wxStandardPaths()
329{
330 // under MSW it's common to use both the applicatio nand vendor
331 UseAppInfo(AppInfo_AppName | AppInfo_VendorName);
332
333 // make it possible to run uninstalled application from the build directory
334 IgnoreAppBuildSubDirs();
335}
336
ac7ad70d
RR
337wxString wxStandardPaths::GetExecutablePath() const
338{
339 return wxGetFullModuleName();
340}
341
40e8ee37
VZ
342wxString wxStandardPaths::GetConfigDir() const
343{
2b147f2e 344 return AppendAppInfo(DoGetDirectory(CSIDL_COMMON_APPDATA));
40e8ee37
VZ
345}
346
347wxString wxStandardPaths::GetUserConfigDir() const
348{
349 return DoGetDirectory(CSIDL_APPDATA);
350}
351
352wxString wxStandardPaths::GetDataDir() const
353{
90537299
VZ
354 // under Windows each program is usually installed in its own directory and
355 // so its datafiles are in the same directory as its main executable
adaa49a8 356 return GetAppDir();
40e8ee37
VZ
357}
358
359wxString wxStandardPaths::GetUserDataDir() const
360{
2b147f2e 361 return AppendAppInfo(GetUserConfigDir());
40e8ee37
VZ
362}
363
364wxString wxStandardPaths::GetUserLocalDataDir() const
365{
2b147f2e 366 return AppendAppInfo(DoGetDirectory(CSIDL_LOCAL_APPDATA));
40e8ee37
VZ
367}
368
369wxString wxStandardPaths::GetPluginsDir() const
370{
adaa49a8
VZ
371 // there is no standard location for plugins, suppose they're in the same
372 // directory as the .exe
373 return GetAppDir();
40e8ee37
VZ
374}
375
40e8ee37
VZ
376// ============================================================================
377// wxStandardPathsWin16 implementation
378// ============================================================================
379
380wxString wxStandardPathsWin16::GetConfigDir() const
381{
382 // this is for compatibility with earlier wxFileConfig versions
383 // which used the Windows directory for the global files
384 wxString dir;
e2072525 385#ifndef __WXWINCE__
40e8ee37
VZ
386 if ( !::GetWindowsDirectory(wxStringBuffer(dir, MAX_PATH), MAX_PATH) )
387 {
9a83f860 388 wxLogLastError(wxT("GetWindowsDirectory"));
40e8ee37 389 }
e2072525 390#else
503602df 391 // TODO: use CSIDL_WINDOWS (eVC4, possibly not eVC3)
4fb9d560 392 dir = wxT("\\Windows");
e2072525 393#endif
40e8ee37
VZ
394
395 return dir;
396}
397
398wxString wxStandardPathsWin16::GetUserConfigDir() const
399{
400 // again, for wxFileConfig which uses $HOME for its user config file
401 return wxGetHomeDir();
402}
403
cd9a8d40 404#endif // wxUSE_STDPATHS