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