Fix assert when adding items with bitmaps wxBitmapComboBox.
[wxWidgets.git] / src / msw / stdpaths.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/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 // Licence: wxWindows licence
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 wxT("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 // ----------------------------------------------------------------------------
84 // module globals
85 // ----------------------------------------------------------------------------
86
87 namespace
88 {
89
90 struct ShellFunctions
91 {
92 ShellFunctions()
93 {
94 pSHGetFolderPath = NULL;
95 pSHGetSpecialFolderPath = NULL;
96 initialized = false;
97 }
98
99 SHGetFolderPath_t pSHGetFolderPath;
100 SHGetSpecialFolderPath_t pSHGetSpecialFolderPath;
101
102 bool initialized;
103 };
104
105 // in spite of using a static variable, this is MT-safe as in the worst case it
106 // results in initializing the function pointer several times -- but this is
107 // harmless
108 ShellFunctions gs_shellFuncs;
109
110 // ----------------------------------------------------------------------------
111 // private functions
112 // ----------------------------------------------------------------------------
113
114 void ResolveShellFunctions()
115 {
116 #if wxUSE_DYNLIB_CLASS
117
118 // start with the newest functions, fall back to the oldest ones
119 #ifdef __WXWINCE__
120 wxString shellDllName(wxT("coredll"));
121 #else
122 // first check for SHGetFolderPath (shell32.dll 5.0)
123 wxString shellDllName(wxT("shell32"));
124 #endif
125
126 wxDynamicLibrary dllShellFunctions( shellDllName );
127 if ( !dllShellFunctions.IsLoaded() )
128 {
129 wxLogTrace(TRACE_MASK, wxT("Failed to load %s.dll"), shellDllName.c_str() );
130 }
131
132 // don't give errors if the functions are unavailable, we're ready to deal
133 // with this
134 wxLogNull noLog;
135
136 #if wxUSE_UNICODE
137 #ifdef __WXWINCE__
138 static const wchar_t UNICODE_SUFFIX = L''; // WinCE SH functions don't seem to have 'W'
139 #else
140 static const wchar_t UNICODE_SUFFIX = L'W';
141 #endif
142 #else // !Unicode
143 static const char UNICODE_SUFFIX = 'A';
144 #endif // Unicode/!Unicode
145
146 wxString funcname(wxT("SHGetFolderPath"));
147 gs_shellFuncs.pSHGetFolderPath =
148 (SHGetFolderPath_t)dllShellFunctions.GetSymbol(funcname + UNICODE_SUFFIX);
149
150 // then for SHGetSpecialFolderPath (shell32.dll 4.71)
151 if ( !gs_shellFuncs.pSHGetFolderPath )
152 {
153 funcname = wxT("SHGetSpecialFolderPath");
154 gs_shellFuncs.pSHGetSpecialFolderPath = (SHGetSpecialFolderPath_t)
155 dllShellFunctions.GetSymbol(funcname + UNICODE_SUFFIX);
156 }
157
158 // finally we fall back on SHGetSpecialFolderLocation (shell32.dll 4.0),
159 // but we don't need to test for it -- it is available even under Win95
160
161 // shell32.dll is going to be unloaded, but it still remains in memory
162 // because we also link to it statically, so it's ok
163
164 gs_shellFuncs.initialized = true;
165 #endif
166 }
167
168 } // anonymous namespace
169
170 // ============================================================================
171 // wxStandardPaths implementation
172 // ============================================================================
173
174 // ----------------------------------------------------------------------------
175 // private helpers
176 // ----------------------------------------------------------------------------
177
178 /* static */
179 wxString wxStandardPaths::DoGetDirectory(int csidl)
180 {
181 if ( !gs_shellFuncs.initialized )
182 ResolveShellFunctions();
183
184 wxString dir;
185 HRESULT hr = E_FAIL;
186
187 // test whether the function is available during compile-time (it must be
188 // defined as either "SHGetFolderPathA" or "SHGetFolderPathW")
189 #ifdef SHGetFolderPath
190 // and now test whether we have it during run-time
191 if ( gs_shellFuncs.pSHGetFolderPath )
192 {
193 hr = gs_shellFuncs.pSHGetFolderPath
194 (
195 NULL, // parent window, not used
196 csidl,
197 NULL, // access token (current user)
198 SHGFP_TYPE_CURRENT, // current path, not just default value
199 wxStringBuffer(dir, MAX_PATH)
200 );
201
202 // somewhat incredibly, the error code in the Unicode version is
203 // different from the one in ASCII version for this function
204 #if wxUSE_UNICODE
205 if ( hr == E_FAIL )
206 #else
207 if ( hr == S_FALSE )
208 #endif
209 {
210 // directory doesn't exist, maybe we can get its default value?
211 hr = gs_shellFuncs.pSHGetFolderPath
212 (
213 NULL,
214 csidl,
215 NULL,
216 SHGFP_TYPE_DEFAULT,
217 wxStringBuffer(dir, MAX_PATH)
218 );
219 }
220 }
221 #endif // SHGetFolderPath
222
223 #ifdef SHGetSpecialFolderPath
224 if ( FAILED(hr) && gs_shellFuncs.pSHGetSpecialFolderPath )
225 {
226 hr = gs_shellFuncs.pSHGetSpecialFolderPath
227 (
228 NULL, // parent window
229 wxStringBuffer(dir, MAX_PATH),
230 csidl,
231 FALSE // don't create if doesn't exist
232 );
233 }
234 #endif // SHGetSpecialFolderPath
235
236 // SHGetSpecialFolderLocation should be available with all compilers and
237 // under all Win32 systems, so don't test for it (and as it doesn't exist
238 // in "A" and "W" versions anyhow, testing would be more involved, too)
239 if ( FAILED(hr) )
240 {
241 LPITEMIDLIST pidl;
242 hr = SHGetSpecialFolderLocation(NULL, csidl, &pidl);
243
244 if ( SUCCEEDED(hr) )
245 {
246 // creating this temp object has (nice) side effect of freeing pidl
247 dir = wxItemIdList(pidl).GetPath();
248 }
249 }
250
251 return dir;
252 }
253
254 wxString wxStandardPaths::GetAppDir() const
255 {
256 if ( m_appDir.empty() )
257 {
258 m_appDir = wxFileName(wxGetFullModuleName()).GetPath();
259 }
260
261 return m_appDir;
262 }
263
264 wxString wxStandardPaths::GetDocumentsDir() const
265 {
266 return DoGetDirectory(CSIDL_PERSONAL);
267 }
268
269 // ----------------------------------------------------------------------------
270 // MSW-specific functions
271 // ----------------------------------------------------------------------------
272
273 void wxStandardPaths::IgnoreAppSubDir(const wxString& subdirPattern)
274 {
275 wxFileName fn = wxFileName::DirName(GetAppDir());
276
277 if ( !fn.GetDirCount() )
278 {
279 // no last directory to ignore anyhow
280 return;
281 }
282
283 const wxString lastdir = fn.GetDirs().Last().Lower();
284 if ( lastdir.Matches(subdirPattern.Lower()) )
285 {
286 fn.RemoveLastDir();
287
288 // store the cached value so that subsequent calls to GetAppDir() will
289 // reuse it instead of using just the program binary directory
290 m_appDir = fn.GetPath();
291 }
292 }
293
294 void wxStandardPaths::IgnoreAppBuildSubDirs()
295 {
296 IgnoreAppSubDir("debug");
297 IgnoreAppSubDir("release");
298
299 wxString compilerPrefix;
300 #ifdef __VISUALC__
301 compilerPrefix = "vc";
302 #elif defined(__GNUG__)
303 compilerPrefix = "gcc";
304 #elif defined(__BORLANDC__)
305 compilerPrefix = "bcc";
306 #elif defined(__DIGITALMARS__)
307 compilerPrefix = "dmc";
308 #elif defined(__WATCOMC__)
309 compilerPrefix = "wat";
310 #else
311 return;
312 #endif
313
314 IgnoreAppSubDir(compilerPrefix + "_msw*");
315 }
316
317 void wxStandardPaths::DontIgnoreAppSubDir()
318 {
319 // this will force the next call to GetAppDir() to use the program binary
320 // path as the application directory
321 m_appDir.clear();
322 }
323
324 /* static */
325 wxString wxStandardPaths::MSWGetShellDir(int csidl)
326 {
327 return DoGetDirectory(csidl);
328 }
329
330 // ----------------------------------------------------------------------------
331 // public functions
332 // ----------------------------------------------------------------------------
333
334 wxStandardPaths::wxStandardPaths()
335 {
336 // make it possible to run uninstalled application from the build directory
337 IgnoreAppBuildSubDirs();
338 }
339
340 wxString wxStandardPaths::GetExecutablePath() const
341 {
342 return wxGetFullModuleName();
343 }
344
345 wxString wxStandardPaths::GetConfigDir() const
346 {
347 return AppendAppInfo(DoGetDirectory(CSIDL_COMMON_APPDATA));
348 }
349
350 wxString wxStandardPaths::GetUserConfigDir() const
351 {
352 return DoGetDirectory(CSIDL_APPDATA);
353 }
354
355 wxString wxStandardPaths::GetDataDir() const
356 {
357 // under Windows each program is usually installed in its own directory and
358 // so its datafiles are in the same directory as its main executable
359 return GetAppDir();
360 }
361
362 wxString wxStandardPaths::GetUserDataDir() const
363 {
364 return AppendAppInfo(GetUserConfigDir());
365 }
366
367 wxString wxStandardPaths::GetUserLocalDataDir() const
368 {
369 return AppendAppInfo(DoGetDirectory(CSIDL_LOCAL_APPDATA));
370 }
371
372 wxString wxStandardPaths::GetPluginsDir() const
373 {
374 // there is no standard location for plugins, suppose they're in the same
375 // directory as the .exe
376 return GetAppDir();
377 }
378
379 // ============================================================================
380 // wxStandardPathsWin16 implementation
381 // ============================================================================
382
383 wxString wxStandardPathsWin16::GetConfigDir() const
384 {
385 // this is for compatibility with earlier wxFileConfig versions
386 // which used the Windows directory for the global files
387 wxString dir;
388 #ifndef __WXWINCE__
389 if ( !::GetWindowsDirectory(wxStringBuffer(dir, MAX_PATH), MAX_PATH) )
390 {
391 wxLogLastError(wxT("GetWindowsDirectory"));
392 }
393 #else
394 // TODO: use CSIDL_WINDOWS (eVC4, possibly not eVC3)
395 dir = wxT("\\Windows");
396 #endif
397
398 return dir;
399 }
400
401 wxString wxStandardPathsWin16::GetUserConfigDir() const
402 {
403 // again, for wxFileConfig which uses $HOME for its user config file
404 return wxGetHomeDir();
405 }
406
407 #endif // wxUSE_STDPATHS