Better fix
[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
744b7316 53#define TRACE_MASK _T("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
40e8ee37
VZ
82// ----------------------------------------------------------------------------
83// module globals
84// ----------------------------------------------------------------------------
85
86struct ShellFunctions
87{
88 ShellFunctions()
89 {
90 pSHGetFolderPath = NULL;
91 pSHGetSpecialFolderPath = NULL;
92 initialized = false;
93 }
94
95 SHGetFolderPath_t pSHGetFolderPath;
96 SHGetSpecialFolderPath_t pSHGetSpecialFolderPath;
97
98 bool initialized;
99};
100
101// in spite of using a static variable, this is MT-safe as in the worst case it
102// results in initializing the function pointer several times -- but this is
103// harmless
104static ShellFunctions gs_shellFuncs;
105
106// ----------------------------------------------------------------------------
107// private functions
108// ----------------------------------------------------------------------------
109
110static void ResolveShellFunctions()
111{
64c288fa
JS
112#if wxUSE_DYNLIB_CLASS
113
40e8ee37 114 // start with the newest functions, fall back to the oldest ones
780d7317
JS
115#ifdef __WXWINCE__
116 wxString shellDllName(_T("coredll"));
117#else
40e8ee37 118 // first check for SHGetFolderPath (shell32.dll 5.0)
780d7317
JS
119 wxString shellDllName(_T("shell32"));
120#endif
121
122 wxDynamicLibrary dllShellFunctions( shellDllName );
123 if ( !dllShellFunctions.IsLoaded() )
40e8ee37 124 {
14e9e56d 125 wxLogTrace(TRACE_MASK, _T("Failed to load %s.dll"), shellDllName.c_str() );
40e8ee37
VZ
126 }
127
780d7317
JS
128 // don't give errors if the functions are unavailable, we're ready to deal
129 // with this
130 wxLogNull noLog;
131
40e8ee37 132#if wxUSE_UNICODE
780d7317
JS
133 #ifdef __WXWINCE__
134 static const wchar_t UNICODE_SUFFIX = L''; // WinCE SH functions don't seem to have 'W'
135 #else
136 static const wchar_t UNICODE_SUFFIX = L'W';
137 #endif
40e8ee37
VZ
138#else // !Unicode
139 static const char UNICODE_SUFFIX = 'A';
140#endif // Unicode/!Unicode
141
142 wxString funcname(_T("SHGetFolderPath"));
143 gs_shellFuncs.pSHGetFolderPath =
780d7317 144 (SHGetFolderPath_t)dllShellFunctions.GetSymbol(funcname + UNICODE_SUFFIX);
40e8ee37
VZ
145
146 // then for SHGetSpecialFolderPath (shell32.dll 4.71)
147 if ( !gs_shellFuncs.pSHGetFolderPath )
148 {
149 funcname = _T("SHGetSpecialFolderPath");
150 gs_shellFuncs.pSHGetSpecialFolderPath = (SHGetSpecialFolderPath_t)
780d7317 151 dllShellFunctions.GetSymbol(funcname + UNICODE_SUFFIX);
40e8ee37
VZ
152 }
153
154 // finally we fall back on SHGetSpecialFolderLocation (shell32.dll 4.0),
155 // but we don't need to test for it -- it is available even under Win95
156
157 // shell32.dll is going to be unloaded, but it still remains in memory
158 // because we also link to it statically, so it's ok
159
160 gs_shellFuncs.initialized = true;
64c288fa 161#endif
40e8ee37
VZ
162}
163
164// ============================================================================
165// wxStandardPaths implementation
166// ============================================================================
167
168// ----------------------------------------------------------------------------
169// private helpers
170// ----------------------------------------------------------------------------
171
172/* static */
173wxString wxStandardPaths::DoGetDirectory(int csidl)
174{
175 if ( !gs_shellFuncs.initialized )
176 ResolveShellFunctions();
177
178 wxString dir;
179 HRESULT hr = E_FAIL;
180
181 // test whether the function is available during compile-time (it must be
182 // defined as either "SHGetFolderPathA" or "SHGetFolderPathW")
183#ifdef SHGetFolderPath
184 // and now test whether we have it during run-time
185 if ( gs_shellFuncs.pSHGetFolderPath )
186 {
187 hr = gs_shellFuncs.pSHGetFolderPath
188 (
189 NULL, // parent window, not used
190 csidl,
191 NULL, // access token (current user)
192 SHGFP_TYPE_CURRENT, // current path, not just default value
193 wxStringBuffer(dir, MAX_PATH)
194 );
195
196 // somewhat incredibly, the error code in the Unicode version is
197 // different from the one in ASCII version for this function
198#if wxUSE_UNICODE
199 if ( hr == E_FAIL )
200#else
201 if ( hr == S_FALSE )
202#endif
203 {
204 // directory doesn't exist, maybe we can get its default value?
205 hr = gs_shellFuncs.pSHGetFolderPath
206 (
207 NULL,
208 csidl,
209 NULL,
210 SHGFP_TYPE_DEFAULT,
211 wxStringBuffer(dir, MAX_PATH)
212 );
213 }
214 }
215#endif // SHGetFolderPath
216
217#ifdef SHGetSpecialFolderPath
218 if ( FAILED(hr) && gs_shellFuncs.pSHGetSpecialFolderPath )
219 {
220 hr = gs_shellFuncs.pSHGetSpecialFolderPath
221 (
222 NULL, // parent window
223 wxStringBuffer(dir, MAX_PATH),
224 csidl,
225 FALSE // don't create if doesn't exist
226 );
227 }
228#endif // SHGetSpecialFolderPath
229
230 // SHGetSpecialFolderLocation should be available with all compilers and
231 // under all Win32 systems, so don't test for it (and as it doesn't exist
232 // in "A" and "W" versions anyhow, testing would be more involved, too)
233 if ( FAILED(hr) )
234 {
235 LPITEMIDLIST pidl;
236 hr = SHGetSpecialFolderLocation(NULL, csidl, &pidl);
237
238 if ( SUCCEEDED(hr) )
239 {
240 // creating this temp object has (nice) side effect of freeing pidl
241 dir = wxItemIdList(pidl).GetPath();
242 }
243 }
244
245 return dir;
246}
247
adaa49a8
VZ
248/* static */
249wxString wxStandardPaths::GetAppDir()
250{
251 wxFileName fn(wxGetFullModuleName());
252
253 // allow running the apps directly from build directory in debug builds
254#ifdef __WXDEBUG__
255 wxString lastdir;
256 if ( fn.GetDirCount() )
257 {
258 lastdir = fn.GetDirs().Last();
259 lastdir.MakeLower();
260 if ( lastdir.Matches(_T("debug*")) || lastdir.Matches(_T("vc_msw*")) )
261 fn.RemoveLastDir();
262 }
263#endif // __WXDEBUG__
264
265 return fn.GetPath();
266}
267
17af82fb
VZ
268wxString wxStandardPaths::GetDocumentsDir() const
269{
270 return DoGetDirectory(CSIDL_PERSONAL);
271}
272
40e8ee37
VZ
273// ----------------------------------------------------------------------------
274// public functions
275// ----------------------------------------------------------------------------
276
ac7ad70d
RR
277wxString wxStandardPaths::GetExecutablePath() const
278{
279 return wxGetFullModuleName();
280}
281
40e8ee37
VZ
282wxString wxStandardPaths::GetConfigDir() const
283{
2b147f2e 284 return AppendAppInfo(DoGetDirectory(CSIDL_COMMON_APPDATA));
40e8ee37
VZ
285}
286
287wxString wxStandardPaths::GetUserConfigDir() const
288{
289 return DoGetDirectory(CSIDL_APPDATA);
290}
291
292wxString wxStandardPaths::GetDataDir() const
293{
90537299
VZ
294 // under Windows each program is usually installed in its own directory and
295 // so its datafiles are in the same directory as its main executable
adaa49a8 296 return GetAppDir();
40e8ee37
VZ
297}
298
299wxString wxStandardPaths::GetUserDataDir() const
300{
2b147f2e 301 return AppendAppInfo(GetUserConfigDir());
40e8ee37
VZ
302}
303
304wxString wxStandardPaths::GetUserLocalDataDir() const
305{
2b147f2e 306 return AppendAppInfo(DoGetDirectory(CSIDL_LOCAL_APPDATA));
40e8ee37
VZ
307}
308
309wxString wxStandardPaths::GetPluginsDir() const
310{
adaa49a8
VZ
311 // there is no standard location for plugins, suppose they're in the same
312 // directory as the .exe
313 return GetAppDir();
40e8ee37
VZ
314}
315
40e8ee37
VZ
316// ============================================================================
317// wxStandardPathsWin16 implementation
318// ============================================================================
319
320wxString wxStandardPathsWin16::GetConfigDir() const
321{
322 // this is for compatibility with earlier wxFileConfig versions
323 // which used the Windows directory for the global files
324 wxString dir;
e2072525 325#ifndef __WXWINCE__
40e8ee37
VZ
326 if ( !::GetWindowsDirectory(wxStringBuffer(dir, MAX_PATH), MAX_PATH) )
327 {
328 wxLogLastError(_T("GetWindowsDirectory"));
329 }
e2072525 330#else
503602df 331 // TODO: use CSIDL_WINDOWS (eVC4, possibly not eVC3)
4fb9d560 332 dir = wxT("\\Windows");
e2072525 333#endif
40e8ee37
VZ
334
335 return dir;
336}
337
338wxString wxStandardPathsWin16::GetUserConfigDir() const
339{
340 // again, for wxFileConfig which uses $HOME for its user config file
341 return wxGetHomeDir();
342}
343
cd9a8d40 344#endif // wxUSE_STDPATHS