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