1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/stdpaths.cpp
3 // Purpose: wxStandardPaths implementation for Win32
4 // Author: Vadim Zeitlin
7 // Copyright: (c) 2004 Vadim Zeitlin <vadim@wxwindows.org>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
28 #include "wx/stdpaths.h"
34 #include "wx/dynlib.h"
35 #include "wx/filename.h"
37 #include "wx/msw/private.h"
38 #include "wx/msw/wrapshl.h"
40 // ----------------------------------------------------------------------------
42 // ----------------------------------------------------------------------------
44 typedef HRESULT (WINAPI
*SHGetFolderPath_t
)(HWND
, int, HANDLE
, DWORD
, LPTSTR
);
45 typedef HRESULT (WINAPI
*SHGetSpecialFolderPath_t
)(HWND
, LPTSTR
, int, BOOL
);
47 // ----------------------------------------------------------------------------
49 // ----------------------------------------------------------------------------
51 // used in our wxLogTrace messages
52 #define TRACE_MASK wxT("stdpaths")
55 #define CSIDL_APPDATA 0x001a
58 #ifndef CSIDL_LOCAL_APPDATA
59 #define CSIDL_LOCAL_APPDATA 0x001c
62 #ifndef CSIDL_COMMON_APPDATA
63 #define CSIDL_COMMON_APPDATA 0x0023
66 #ifndef CSIDL_PROGRAM_FILES
67 #define CSIDL_PROGRAM_FILES 0x0026
70 #ifndef CSIDL_PERSONAL
71 #define CSIDL_PERSONAL 0x0005
74 #ifndef SHGFP_TYPE_CURRENT
75 #define SHGFP_TYPE_CURRENT 0
78 #ifndef SHGFP_TYPE_DEFAULT
79 #define SHGFP_TYPE_DEFAULT 1
82 // ----------------------------------------------------------------------------
84 // ----------------------------------------------------------------------------
93 pSHGetFolderPath
= NULL
;
94 pSHGetSpecialFolderPath
= NULL
;
98 SHGetFolderPath_t pSHGetFolderPath
;
99 SHGetSpecialFolderPath_t pSHGetSpecialFolderPath
;
104 // in spite of using a static variable, this is MT-safe as in the worst case it
105 // results in initializing the function pointer several times -- but this is
107 ShellFunctions gs_shellFuncs
;
109 // ----------------------------------------------------------------------------
111 // ----------------------------------------------------------------------------
113 void ResolveShellFunctions()
115 #if wxUSE_DYNLIB_CLASS
117 // start with the newest functions, fall back to the oldest ones
119 wxString
shellDllName(wxT("coredll"));
121 // first check for SHGetFolderPath (shell32.dll 5.0)
122 wxString
shellDllName(wxT("shell32"));
125 wxDynamicLibrary
dllShellFunctions( shellDllName
);
126 if ( !dllShellFunctions
.IsLoaded() )
128 wxLogTrace(TRACE_MASK
, wxT("Failed to load %s.dll"), shellDllName
.c_str() );
131 // don't give errors if the functions are unavailable, we're ready to deal
137 static const wchar_t UNICODE_SUFFIX
= L
''; // WinCE SH functions don't seem to have 'W'
139 static const wchar_t UNICODE_SUFFIX
= L
'W';
142 static const char UNICODE_SUFFIX
= 'A';
143 #endif // Unicode/!Unicode
145 wxString
funcname(wxT("SHGetFolderPath"));
146 gs_shellFuncs
.pSHGetFolderPath
=
147 (SHGetFolderPath_t
)dllShellFunctions
.GetSymbol(funcname
+ UNICODE_SUFFIX
);
149 // then for SHGetSpecialFolderPath (shell32.dll 4.71)
150 if ( !gs_shellFuncs
.pSHGetFolderPath
)
152 funcname
= wxT("SHGetSpecialFolderPath");
153 gs_shellFuncs
.pSHGetSpecialFolderPath
= (SHGetSpecialFolderPath_t
)
154 dllShellFunctions
.GetSymbol(funcname
+ UNICODE_SUFFIX
);
157 // finally we fall back on SHGetSpecialFolderLocation (shell32.dll 4.0),
158 // but we don't need to test for it -- it is available even under Win95
160 // shell32.dll is going to be unloaded, but it still remains in memory
161 // because we also link to it statically, so it's ok
163 gs_shellFuncs
.initialized
= true;
167 } // anonymous namespace
169 // ============================================================================
170 // wxStandardPaths implementation
171 // ============================================================================
173 // ----------------------------------------------------------------------------
175 // ----------------------------------------------------------------------------
178 wxString
wxStandardPaths::DoGetDirectory(int csidl
)
180 if ( !gs_shellFuncs
.initialized
)
181 ResolveShellFunctions();
186 // test whether the function is available during compile-time (it must be
187 // defined as either "SHGetFolderPathA" or "SHGetFolderPathW")
188 #ifdef SHGetFolderPath
189 // and now test whether we have it during run-time
190 if ( gs_shellFuncs
.pSHGetFolderPath
)
192 hr
= gs_shellFuncs
.pSHGetFolderPath
194 NULL
, // parent window, not used
196 NULL
, // access token (current user)
197 SHGFP_TYPE_CURRENT
, // current path, not just default value
198 wxStringBuffer(dir
, MAX_PATH
)
201 // somewhat incredibly, the error code in the Unicode version is
202 // different from the one in ASCII version for this function
209 // directory doesn't exist, maybe we can get its default value?
210 hr
= gs_shellFuncs
.pSHGetFolderPath
216 wxStringBuffer(dir
, MAX_PATH
)
220 #endif // SHGetFolderPath
222 #ifdef SHGetSpecialFolderPath
223 if ( FAILED(hr
) && gs_shellFuncs
.pSHGetSpecialFolderPath
)
225 hr
= gs_shellFuncs
.pSHGetSpecialFolderPath
227 NULL
, // parent window
228 wxStringBuffer(dir
, MAX_PATH
),
230 FALSE
// don't create if doesn't exist
233 #endif // SHGetSpecialFolderPath
235 // SHGetSpecialFolderLocation should be available with all compilers and
236 // under all Win32 systems, so don't test for it (and as it doesn't exist
237 // in "A" and "W" versions anyhow, testing would be more involved, too)
241 hr
= SHGetSpecialFolderLocation(NULL
, csidl
, &pidl
);
245 // creating this temp object has (nice) side effect of freeing pidl
246 dir
= wxItemIdList(pidl
).GetPath();
253 wxString
wxStandardPaths::GetAppDir() const
255 if ( m_appDir
.empty() )
257 m_appDir
= wxFileName(wxGetFullModuleName()).GetPath();
263 wxString
wxStandardPaths::GetDocumentsDir() const
265 return DoGetDirectory(CSIDL_PERSONAL
);
268 // ----------------------------------------------------------------------------
269 // MSW-specific functions
270 // ----------------------------------------------------------------------------
272 void wxStandardPaths::IgnoreAppSubDir(const wxString
& subdirPattern
)
274 wxFileName fn
= wxFileName::DirName(GetAppDir());
276 if ( !fn
.GetDirCount() )
278 // no last directory to ignore anyhow
282 const wxString lastdir
= fn
.GetDirs().Last().Lower();
283 if ( lastdir
.Matches(subdirPattern
.Lower()) )
287 // store the cached value so that subsequent calls to GetAppDir() will
288 // reuse it instead of using just the program binary directory
289 m_appDir
= fn
.GetPath();
293 void wxStandardPaths::IgnoreAppBuildSubDirs()
295 IgnoreAppSubDir("debug");
296 IgnoreAppSubDir("release");
298 wxString compilerPrefix
;
300 compilerPrefix
= "vc";
301 #elif defined(__GNUG__)
302 compilerPrefix
= "gcc";
303 #elif defined(__BORLANDC__)
304 compilerPrefix
= "bcc";
305 #elif defined(__DIGITALMARS__)
306 compilerPrefix
= "dmc";
307 #elif defined(__WATCOMC__)
308 compilerPrefix
= "wat";
313 IgnoreAppSubDir(compilerPrefix
+ "_msw*");
316 void wxStandardPaths::DontIgnoreAppSubDir()
318 // this will force the next call to GetAppDir() to use the program binary
319 // path as the application directory
324 wxString
wxStandardPaths::MSWGetShellDir(int csidl
)
326 return DoGetDirectory(csidl
);
329 // ----------------------------------------------------------------------------
331 // ----------------------------------------------------------------------------
333 wxStandardPaths::wxStandardPaths()
335 // make it possible to run uninstalled application from the build directory
336 IgnoreAppBuildSubDirs();
339 wxString
wxStandardPaths::GetExecutablePath() const
341 return wxGetFullModuleName();
344 wxString
wxStandardPaths::GetConfigDir() const
346 return AppendAppInfo(DoGetDirectory(CSIDL_COMMON_APPDATA
));
349 wxString
wxStandardPaths::GetUserConfigDir() const
351 return DoGetDirectory(CSIDL_APPDATA
);
354 wxString
wxStandardPaths::GetDataDir() const
356 // under Windows each program is usually installed in its own directory and
357 // so its datafiles are in the same directory as its main executable
361 wxString
wxStandardPaths::GetUserDataDir() const
363 return AppendAppInfo(GetUserConfigDir());
366 wxString
wxStandardPaths::GetUserLocalDataDir() const
368 return AppendAppInfo(DoGetDirectory(CSIDL_LOCAL_APPDATA
));
371 wxString
wxStandardPaths::GetPluginsDir() const
373 // there is no standard location for plugins, suppose they're in the same
374 // directory as the .exe
378 // ============================================================================
379 // wxStandardPathsWin16 implementation
380 // ============================================================================
382 wxString
wxStandardPathsWin16::GetConfigDir() const
384 // this is for compatibility with earlier wxFileConfig versions
385 // which used the Windows directory for the global files
388 if ( !::GetWindowsDirectory(wxStringBuffer(dir
, MAX_PATH
), MAX_PATH
) )
390 wxLogLastError(wxT("GetWindowsDirectory"));
393 // TODO: use CSIDL_WINDOWS (eVC4, possibly not eVC3)
394 dir
= wxT("\\Windows");
400 wxString
wxStandardPathsWin16::GetUserConfigDir() const
402 // again, for wxFileConfig which uses $HOME for its user config file
403 return wxGetHomeDir();
406 #endif // wxUSE_STDPATHS