allow to optionally use vendor name component in standard paths (slightly modified...
[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 #include "wx/stdpaths.h"
30
31 #ifndef WX_PRECOMP
32 #include "wx/utils.h"
33 #endif //WX_PRECOMP
34
35 #include "wx/dynlib.h"
36 #include "wx/filename.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 #define 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 CSIDL_PERSONAL
72 #define CSIDL_PERSONAL 0x0005
73 #endif
74
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
82 // ----------------------------------------------------------------------------
83 // module globals
84 // ----------------------------------------------------------------------------
85
86 struct 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
104 static ShellFunctions gs_shellFuncs;
105
106 // ----------------------------------------------------------------------------
107 // private functions
108 // ----------------------------------------------------------------------------
109
110 static void ResolveShellFunctions()
111 {
112 #if wxUSE_DYNLIB_CLASS
113
114 // start with the newest functions, fall back to the oldest ones
115 #ifdef __WXWINCE__
116 wxString shellDllName(_T("coredll"));
117 #else
118 // first check for SHGetFolderPath (shell32.dll 5.0)
119 wxString shellDllName(_T("shell32"));
120 #endif
121
122 wxDynamicLibrary dllShellFunctions( shellDllName );
123 if ( !dllShellFunctions.IsLoaded() )
124 {
125 wxLogTrace(TRACE_MASK, _T("Failed to load %s.dll"), shellDllName.c_str() );
126 }
127
128 // don't give errors if the functions are unavailable, we're ready to deal
129 // with this
130 wxLogNull noLog;
131
132 #if wxUSE_UNICODE
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
138 #else // !Unicode
139 static const char UNICODE_SUFFIX = 'A';
140 #endif // Unicode/!Unicode
141
142 wxString funcname(_T("SHGetFolderPath"));
143 gs_shellFuncs.pSHGetFolderPath =
144 (SHGetFolderPath_t)dllShellFunctions.GetSymbol(funcname + UNICODE_SUFFIX);
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)
151 dllShellFunctions.GetSymbol(funcname + UNICODE_SUFFIX);
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;
161 #endif
162 }
163
164 // ============================================================================
165 // wxStandardPaths implementation
166 // ============================================================================
167
168 // ----------------------------------------------------------------------------
169 // private helpers
170 // ----------------------------------------------------------------------------
171
172 /* static */
173 wxString 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
248 /* static */
249 wxString 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
268 wxString wxStandardPaths::GetDocumentsDir() const
269 {
270 return DoGetDirectory(CSIDL_PERSONAL);
271 }
272
273 // ----------------------------------------------------------------------------
274 // public functions
275 // ----------------------------------------------------------------------------
276
277 wxString wxStandardPaths::GetExecutablePath() const
278 {
279 return wxGetFullModuleName();
280 }
281
282 wxString wxStandardPaths::GetConfigDir() const
283 {
284 return AppendAppInfo(DoGetDirectory(CSIDL_COMMON_APPDATA));
285 }
286
287 wxString wxStandardPaths::GetUserConfigDir() const
288 {
289 return DoGetDirectory(CSIDL_APPDATA);
290 }
291
292 wxString wxStandardPaths::GetDataDir() const
293 {
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
296 return GetAppDir();
297 }
298
299 wxString wxStandardPaths::GetUserDataDir() const
300 {
301 return AppendAppInfo(GetUserConfigDir());
302 }
303
304 wxString wxStandardPaths::GetUserLocalDataDir() const
305 {
306 return AppendAppInfo(DoGetDirectory(CSIDL_LOCAL_APPDATA));
307 }
308
309 wxString wxStandardPaths::GetPluginsDir() const
310 {
311 // there is no standard location for plugins, suppose they're in the same
312 // directory as the .exe
313 return GetAppDir();
314 }
315
316 // ============================================================================
317 // wxStandardPathsWin16 implementation
318 // ============================================================================
319
320 wxString 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;
325 #ifndef __WXWINCE__
326 if ( !::GetWindowsDirectory(wxStringBuffer(dir, MAX_PATH), MAX_PATH) )
327 {
328 wxLogLastError(_T("GetWindowsDirectory"));
329 }
330 #else
331 // TODO: use CSIDL_WINDOWS (eVC4, possibly not eVC3)
332 dir = wxT("\\Windows");
333 #endif
334
335 return dir;
336 }
337
338 wxString wxStandardPathsWin16::GetUserConfigDir() const
339 {
340 // again, for wxFileConfig which uses $HOME for its user config file
341 return wxGetHomeDir();
342 }
343
344 #endif // wxUSE_STDPATHS