]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/stdpaths.cpp
Enable variadic macros for VC9 and later.
[wxWidgets.git] / src / msw / stdpaths.cpp
... / ...
CommitLineData
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
45typedef HRESULT (WINAPI *SHGetFolderPath_t)(HWND, int, HANDLE, DWORD, LPTSTR);
46typedef 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
87namespace
88{
89
90struct 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
108ShellFunctions gs_shellFuncs;
109
110// ----------------------------------------------------------------------------
111// private functions
112// ----------------------------------------------------------------------------
113
114void 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 */
179wxString 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
254wxString wxStandardPaths::GetAppDir() const
255{
256 if ( m_appDir.empty() )
257 {
258 m_appDir = wxFileName(wxGetFullModuleName()).GetPath();
259 }
260
261 return m_appDir;
262}
263
264wxString wxStandardPaths::GetDocumentsDir() const
265{
266 return DoGetDirectory(CSIDL_PERSONAL);
267}
268
269// ----------------------------------------------------------------------------
270// MSW-specific functions
271// ----------------------------------------------------------------------------
272
273void 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
294void 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
317void 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 */
325wxString wxStandardPaths::MSWGetShellDir(int csidl)
326{
327 return DoGetDirectory(csidl);
328}
329
330// ----------------------------------------------------------------------------
331// public functions
332// ----------------------------------------------------------------------------
333
334wxStandardPaths::wxStandardPaths()
335{
336 // make it possible to run uninstalled application from the build directory
337 IgnoreAppBuildSubDirs();
338}
339
340wxString wxStandardPaths::GetExecutablePath() const
341{
342 return wxGetFullModuleName();
343}
344
345wxString wxStandardPaths::GetConfigDir() const
346{
347 return AppendAppInfo(DoGetDirectory(CSIDL_COMMON_APPDATA));
348}
349
350wxString wxStandardPaths::GetUserConfigDir() const
351{
352 return DoGetDirectory(CSIDL_APPDATA);
353}
354
355wxString 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
362wxString wxStandardPaths::GetUserDataDir() const
363{
364 return AppendAppInfo(GetUserConfigDir());
365}
366
367wxString wxStandardPaths::GetUserLocalDataDir() const
368{
369 return AppendAppInfo(DoGetDirectory(CSIDL_LOCAL_APPDATA));
370}
371
372wxString 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
383wxString 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
401wxString 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