1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: msw/stdpaths.cpp
3 // Purpose: wxStandardPaths implementation for Win32
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 2004 Vadim Zeitlin <vadim@wxwindows.org>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // for compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
29 #include "wx/stdpaths.h"
35 #include "wx/dynlib.h"
36 #include "wx/filename.h"
38 #include "wx/msw/private.h"
39 #include "wx/msw/wrapshl.h"
41 // ----------------------------------------------------------------------------
43 // ----------------------------------------------------------------------------
45 typedef HRESULT (WINAPI
*SHGetFolderPath_t
)(HWND
, int, HANDLE
, DWORD
, LPTSTR
);
46 typedef HRESULT (WINAPI
*SHGetSpecialFolderPath_t
)(HWND
, LPTSTR
, int, BOOL
);
48 // ----------------------------------------------------------------------------
50 // ----------------------------------------------------------------------------
52 // used in our wxLogTrace messages
53 #define TRACE_MASK wxT("stdpaths")
56 #define CSIDL_APPDATA 0x001a
59 #ifndef CSIDL_LOCAL_APPDATA
60 #define CSIDL_LOCAL_APPDATA 0x001c
63 #ifndef CSIDL_COMMON_APPDATA
64 #define CSIDL_COMMON_APPDATA 0x0023
67 #ifndef CSIDL_PROGRAM_FILES
68 #define CSIDL_PROGRAM_FILES 0x0026
71 #ifndef CSIDL_PERSONAL
72 #define CSIDL_PERSONAL 0x0005
75 #ifndef SHGFP_TYPE_CURRENT
76 #define SHGFP_TYPE_CURRENT 0
79 #ifndef SHGFP_TYPE_DEFAULT
80 #define SHGFP_TYPE_DEFAULT 1
83 // ----------------------------------------------------------------------------
85 // ----------------------------------------------------------------------------
94 pSHGetFolderPath
= NULL
;
95 pSHGetSpecialFolderPath
= NULL
;
99 SHGetFolderPath_t pSHGetFolderPath
;
100 SHGetSpecialFolderPath_t pSHGetSpecialFolderPath
;
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
108 ShellFunctions gs_shellFuncs
;
110 // ----------------------------------------------------------------------------
112 // ----------------------------------------------------------------------------
114 void ResolveShellFunctions()
116 #if wxUSE_DYNLIB_CLASS
118 // start with the newest functions, fall back to the oldest ones
120 wxString
shellDllName(wxT("coredll"));
122 // first check for SHGetFolderPath (shell32.dll 5.0)
123 wxString
shellDllName(wxT("shell32"));
126 wxDynamicLibrary
dllShellFunctions( shellDllName
);
127 if ( !dllShellFunctions
.IsLoaded() )
129 wxLogTrace(TRACE_MASK
, wxT("Failed to load %s.dll"), shellDllName
.c_str() );
132 // don't give errors if the functions are unavailable, we're ready to deal
138 static const wchar_t UNICODE_SUFFIX
= L
''; // WinCE SH functions don't seem to have 'W'
140 static const wchar_t UNICODE_SUFFIX
= L
'W';
143 static const char UNICODE_SUFFIX
= 'A';
144 #endif // Unicode/!Unicode
146 wxString
funcname(wxT("SHGetFolderPath"));
147 gs_shellFuncs
.pSHGetFolderPath
=
148 (SHGetFolderPath_t
)dllShellFunctions
.GetSymbol(funcname
+ UNICODE_SUFFIX
);
150 // then for SHGetSpecialFolderPath (shell32.dll 4.71)
151 if ( !gs_shellFuncs
.pSHGetFolderPath
)
153 funcname
= wxT("SHGetSpecialFolderPath");
154 gs_shellFuncs
.pSHGetSpecialFolderPath
= (SHGetSpecialFolderPath_t
)
155 dllShellFunctions
.GetSymbol(funcname
+ UNICODE_SUFFIX
);
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
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
164 gs_shellFuncs
.initialized
= true;
168 } // anonymous namespace
170 // ============================================================================
171 // wxStandardPaths implementation
172 // ============================================================================
174 // ----------------------------------------------------------------------------
176 // ----------------------------------------------------------------------------
179 wxString
wxStandardPaths::DoGetDirectory(int csidl
)
181 if ( !gs_shellFuncs
.initialized
)
182 ResolveShellFunctions();
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
)
193 hr
= gs_shellFuncs
.pSHGetFolderPath
195 NULL
, // parent window, not used
197 NULL
, // access token (current user)
198 SHGFP_TYPE_CURRENT
, // current path, not just default value
199 wxStringBuffer(dir
, MAX_PATH
)
202 // somewhat incredibly, the error code in the Unicode version is
203 // different from the one in ASCII version for this function
210 // directory doesn't exist, maybe we can get its default value?
211 hr
= gs_shellFuncs
.pSHGetFolderPath
217 wxStringBuffer(dir
, MAX_PATH
)
221 #endif // SHGetFolderPath
223 #ifdef SHGetSpecialFolderPath
224 if ( FAILED(hr
) && gs_shellFuncs
.pSHGetSpecialFolderPath
)
226 hr
= gs_shellFuncs
.pSHGetSpecialFolderPath
228 NULL
, // parent window
229 wxStringBuffer(dir
, MAX_PATH
),
231 FALSE
// don't create if doesn't exist
234 #endif // SHGetSpecialFolderPath
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)
242 hr
= SHGetSpecialFolderLocation(NULL
, csidl
, &pidl
);
246 // creating this temp object has (nice) side effect of freeing pidl
247 dir
= wxItemIdList(pidl
).GetPath();
254 wxString
wxStandardPaths::GetAppDir() const
256 if ( m_appDir
.empty() )
258 m_appDir
= wxFileName(wxGetFullModuleName()).GetPath();
264 wxString
wxStandardPaths::GetDocumentsDir() const
266 return DoGetDirectory(CSIDL_PERSONAL
);
269 // ----------------------------------------------------------------------------
270 // MSW-specific functions
271 // ----------------------------------------------------------------------------
273 void wxStandardPaths::IgnoreAppSubDir(const wxString
& subdirPattern
)
275 wxFileName fn
= wxFileName::DirName(GetAppDir());
277 if ( !fn
.GetDirCount() )
279 // no last directory to ignore anyhow
283 const wxString lastdir
= fn
.GetDirs().Last().Lower();
284 if ( lastdir
.Matches(subdirPattern
.Lower()) )
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();
294 void wxStandardPaths::IgnoreAppBuildSubDirs()
296 IgnoreAppSubDir("debug");
297 IgnoreAppSubDir("release");
299 wxString compilerPrefix
;
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";
314 IgnoreAppSubDir(compilerPrefix
+ "_msw*");
317 void wxStandardPaths::DontIgnoreAppSubDir()
319 // this will force the next call to GetAppDir() to use the program binary
320 // path as the application directory
325 wxString
wxStandardPaths::MSWGetShellDir(int csidl
)
327 return DoGetDirectory(csidl
);
330 // ----------------------------------------------------------------------------
332 // ----------------------------------------------------------------------------
334 wxStandardPaths::wxStandardPaths()
336 // make it possible to run uninstalled application from the build directory
337 IgnoreAppBuildSubDirs();
340 wxString
wxStandardPaths::GetExecutablePath() const
342 return wxGetFullModuleName();
345 wxString
wxStandardPaths::GetConfigDir() const
347 return AppendAppInfo(DoGetDirectory(CSIDL_COMMON_APPDATA
));
350 wxString
wxStandardPaths::GetUserConfigDir() const
352 return DoGetDirectory(CSIDL_APPDATA
);
355 wxString
wxStandardPaths::GetDataDir() const
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
362 wxString
wxStandardPaths::GetUserDataDir() const
364 return AppendAppInfo(GetUserConfigDir());
367 wxString
wxStandardPaths::GetUserLocalDataDir() const
369 return AppendAppInfo(DoGetDirectory(CSIDL_LOCAL_APPDATA
));
372 wxString
wxStandardPaths::GetPluginsDir() const
374 // there is no standard location for plugins, suppose they're in the same
375 // directory as the .exe
379 // ============================================================================
380 // wxStandardPathsWin16 implementation
381 // ============================================================================
383 wxString
wxStandardPathsWin16::GetConfigDir() const
385 // this is for compatibility with earlier wxFileConfig versions
386 // which used the Windows directory for the global files
389 if ( !::GetWindowsDirectory(wxStringBuffer(dir
, MAX_PATH
), MAX_PATH
) )
391 wxLogLastError(wxT("GetWindowsDirectory"));
394 // TODO: use CSIDL_WINDOWS (eVC4, possibly not eVC3)
395 dir
= wxT("\\Windows");
401 wxString
wxStandardPathsWin16::GetUserConfigDir() const
403 // again, for wxFileConfig which uses $HOME for its user config file
404 return wxGetHomeDir();
407 #endif // wxUSE_STDPATHS