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