added wxUSE_STDPATHS
[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 // don't give errors if the functions are unavailable, we're ready to deal
110 // with this
111 wxLogNull noLog;
112
113 // start with the newest functions, fall back to the oldest ones
114
115 // first check for SHGetFolderPath (shell32.dll 5.0)
116 wxDynamicLibrary dllShell32(_T("shell32"));
117 if ( !dllShell32.IsLoaded() )
118 {
119 wxLogTrace(TRACE_MASK, _T("Failed to load shell32.dll"));
120 }
121
122 #if wxUSE_UNICODE
123 static const wchar_t UNICODE_SUFFIX = L'W';
124 #else // !Unicode
125 static const char UNICODE_SUFFIX = 'A';
126 #endif // Unicode/!Unicode
127
128 wxString funcname(_T("SHGetFolderPath"));
129 gs_shellFuncs.pSHGetFolderPath =
130 (SHGetFolderPath_t)dllShell32.GetSymbol(funcname + UNICODE_SUFFIX);
131
132 // then for SHGetSpecialFolderPath (shell32.dll 4.71)
133 if ( !gs_shellFuncs.pSHGetFolderPath )
134 {
135 funcname = _T("SHGetSpecialFolderPath");
136 gs_shellFuncs.pSHGetSpecialFolderPath = (SHGetSpecialFolderPath_t)
137 dllShell32.GetSymbol(funcname + UNICODE_SUFFIX);
138 }
139
140 // finally we fall back on SHGetSpecialFolderLocation (shell32.dll 4.0),
141 // but we don't need to test for it -- it is available even under Win95
142
143 // shell32.dll is going to be unloaded, but it still remains in memory
144 // because we also link to it statically, so it's ok
145
146 gs_shellFuncs.initialized = true;
147 }
148
149 // ============================================================================
150 // wxStandardPaths implementation
151 // ============================================================================
152
153 // ----------------------------------------------------------------------------
154 // private helpers
155 // ----------------------------------------------------------------------------
156
157 /* static */
158 wxString wxStandardPaths::DoGetDirectory(int csidl)
159 {
160 if ( !gs_shellFuncs.initialized )
161 ResolveShellFunctions();
162
163 wxString dir;
164 HRESULT hr = E_FAIL;
165
166 // test whether the function is available during compile-time (it must be
167 // defined as either "SHGetFolderPathA" or "SHGetFolderPathW")
168 #ifdef SHGetFolderPath
169 // and now test whether we have it during run-time
170 if ( gs_shellFuncs.pSHGetFolderPath )
171 {
172 hr = gs_shellFuncs.pSHGetFolderPath
173 (
174 NULL, // parent window, not used
175 csidl,
176 NULL, // access token (current user)
177 SHGFP_TYPE_CURRENT, // current path, not just default value
178 wxStringBuffer(dir, MAX_PATH)
179 );
180
181 // somewhat incredibly, the error code in the Unicode version is
182 // different from the one in ASCII version for this function
183 #if wxUSE_UNICODE
184 if ( hr == E_FAIL )
185 #else
186 if ( hr == S_FALSE )
187 #endif
188 {
189 // directory doesn't exist, maybe we can get its default value?
190 hr = gs_shellFuncs.pSHGetFolderPath
191 (
192 NULL,
193 csidl,
194 NULL,
195 SHGFP_TYPE_DEFAULT,
196 wxStringBuffer(dir, MAX_PATH)
197 );
198 }
199 }
200 #endif // SHGetFolderPath
201
202 #ifdef SHGetSpecialFolderPath
203 if ( FAILED(hr) && gs_shellFuncs.pSHGetSpecialFolderPath )
204 {
205 hr = gs_shellFuncs.pSHGetSpecialFolderPath
206 (
207 NULL, // parent window
208 wxStringBuffer(dir, MAX_PATH),
209 csidl,
210 FALSE // don't create if doesn't exist
211 );
212 }
213 #endif // SHGetSpecialFolderPath
214
215 // SHGetSpecialFolderLocation should be available with all compilers and
216 // under all Win32 systems, so don't test for it (and as it doesn't exist
217 // in "A" and "W" versions anyhow, testing would be more involved, too)
218 if ( FAILED(hr) )
219 {
220 LPITEMIDLIST pidl;
221 hr = SHGetSpecialFolderLocation(NULL, csidl, &pidl);
222
223 if ( SUCCEEDED(hr) )
224 {
225 // creating this temp object has (nice) side effect of freeing pidl
226 dir = wxItemIdList(pidl).GetPath();
227 }
228 }
229
230 return dir;
231 }
232
233 // ----------------------------------------------------------------------------
234 // public functions
235 // ----------------------------------------------------------------------------
236
237 wxString wxStandardPaths::GetConfigDir() const
238 {
239 return AppendAppName(DoGetDirectory(CSIDL_COMMON_APPDATA));
240 }
241
242 wxString wxStandardPaths::GetUserConfigDir() const
243 {
244 return DoGetDirectory(CSIDL_APPDATA);
245 }
246
247 wxString wxStandardPaths::GetDataDir() const
248 {
249 return AppendAppName(DoGetDirectory(CSIDL_PROGRAM_FILES));
250 }
251
252 wxString wxStandardPaths::GetUserDataDir() const
253 {
254 return AppendAppName(GetUserConfigDir());
255 }
256
257 wxString wxStandardPaths::GetUserLocalDataDir() const
258 {
259 return AppendAppName(DoGetDirectory(CSIDL_LOCAL_APPDATA));
260 }
261
262 wxString wxStandardPaths::GetPluginsDir() const
263 {
264 return wxFileName(wxGetFullModuleName()).GetPath();
265 }
266
267
268 // ============================================================================
269 // wxStandardPathsWin16 implementation
270 // ============================================================================
271
272 wxString wxStandardPathsWin16::GetConfigDir() const
273 {
274 // this is for compatibility with earlier wxFileConfig versions
275 // which used the Windows directory for the global files
276 wxString dir;
277 #ifndef __WXWINCE__
278 if ( !::GetWindowsDirectory(wxStringBuffer(dir, MAX_PATH), MAX_PATH) )
279 {
280 wxLogLastError(_T("GetWindowsDirectory"));
281 }
282 #else
283 // TODO:
284 // eVC4 - use CSIDL_WINDOWS
285 // eVC3 - probably not possible through API
286 #endif
287
288 return dir;
289 }
290
291 wxString wxStandardPathsWin16::GetUserConfigDir() const
292 {
293 // again, for wxFileConfig which uses $HOME for its user config file
294 return wxGetHomeDir();
295 }
296
297 #endif // wxUSE_STDPATHS