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: stdpaths.cpp 51807 2008-02-15 13:14:49Z VZ $
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 {
ShellFunctionsShellFunctions88     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 
ResolveShellFunctions()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 */
DoGetDirectory(int csidl)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 */
GetAppDir()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 
GetDocumentsDir() const268 wxString wxStandardPaths::GetDocumentsDir() const
269 {
270     return DoGetDirectory(CSIDL_PERSONAL);
271 }
272 
273 // ----------------------------------------------------------------------------
274 // public functions
275 // ----------------------------------------------------------------------------
276 
GetExecutablePath() const277 wxString wxStandardPaths::GetExecutablePath() const
278 {
279     return wxGetFullModuleName();
280 }
281 
GetConfigDir() const282 wxString wxStandardPaths::GetConfigDir() const
283 {
284     return AppendAppName(DoGetDirectory(CSIDL_COMMON_APPDATA));
285 }
286 
GetUserConfigDir() const287 wxString wxStandardPaths::GetUserConfigDir() const
288 {
289     return DoGetDirectory(CSIDL_APPDATA);
290 }
291 
GetDataDir() const292 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 
GetUserDataDir() const299 wxString wxStandardPaths::GetUserDataDir() const
300 {
301     return AppendAppName(GetUserConfigDir());
302 }
303 
GetUserLocalDataDir() const304 wxString wxStandardPaths::GetUserLocalDataDir() const
305 {
306     return AppendAppName(DoGetDirectory(CSIDL_LOCAL_APPDATA));
307 }
308 
GetPluginsDir() const309 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 
GetConfigDir() const320 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 
GetUserConfigDir() const338 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
345