]> git.saurik.com Git - wxWidgets.git/blame - src/msw/stdpaths.cpp
Don't use DDEExec registry key in wxMSW wxExecute() if it's empty.
[wxWidgets.git] / src / msw / stdpaths.cpp
CommitLineData
40e8ee37 1///////////////////////////////////////////////////////////////////////////////
80fdcdb9 2// Name: src/msw/stdpaths.cpp
40e8ee37
VZ
3// Purpose: wxStandardPaths implementation for Win32
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 2004-10-19
40e8ee37 7// Copyright: (c) 2004 Vadim Zeitlin <vadim@wxwindows.org>
526954c5 8// Licence: wxWindows licence
40e8ee37
VZ
9///////////////////////////////////////////////////////////////////////////////
10
11// ============================================================================
12// declarations
13// ============================================================================
14
15// ----------------------------------------------------------------------------
16// headers
17// ----------------------------------------------------------------------------
18
19// for compilers that support precompilation, includes "wx.h".
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
23 #pragma hdrstop
24#endif
25
cd9a8d40
VZ
26#if wxUSE_STDPATHS
27
de303444
MW
28#include "wx/stdpaths.h"
29
40e8ee37 30#ifndef WX_PRECOMP
de303444 31 #include "wx/utils.h"
40e8ee37
VZ
32#endif //WX_PRECOMP
33
34#include "wx/dynlib.h"
35#include "wx/filename.h"
36
40e8ee37
VZ
37#include "wx/msw/private.h"
38#include "wx/msw/wrapshl.h"
39
40// ----------------------------------------------------------------------------
41// types
42// ----------------------------------------------------------------------------
43
44typedef HRESULT (WINAPI *SHGetFolderPath_t)(HWND, int, HANDLE, DWORD, LPTSTR);
45typedef HRESULT (WINAPI *SHGetSpecialFolderPath_t)(HWND, LPTSTR, int, BOOL);
46
47// ----------------------------------------------------------------------------
48// constants
49// ----------------------------------------------------------------------------
50
51// used in our wxLogTrace messages
9a83f860 52#define TRACE_MASK wxT("stdpaths")
40e8ee37 53
61c2afed
WS
54#ifndef CSIDL_APPDATA
55 #define CSIDL_APPDATA 0x001a
56#endif
57
40e8ee37
VZ
58#ifndef CSIDL_LOCAL_APPDATA
59 #define CSIDL_LOCAL_APPDATA 0x001c
60#endif
61
62#ifndef CSIDL_COMMON_APPDATA
63 #define CSIDL_COMMON_APPDATA 0x0023
64#endif
65
66#ifndef CSIDL_PROGRAM_FILES
67 #define CSIDL_PROGRAM_FILES 0x0026
68#endif
69
17af82fb
VZ
70#ifndef CSIDL_PERSONAL
71 #define CSIDL_PERSONAL 0x0005
72#endif
73
cd0c4800
WS
74#ifndef SHGFP_TYPE_CURRENT
75 #define SHGFP_TYPE_CURRENT 0
76#endif
77
78#ifndef SHGFP_TYPE_DEFAULT
79 #define SHGFP_TYPE_DEFAULT 1
80#endif
4cd15b49 81
40e8ee37
VZ
82// ----------------------------------------------------------------------------
83// module globals
84// ----------------------------------------------------------------------------
85
4cd15b49
VZ
86namespace
87{
88
40e8ee37
VZ
89struct ShellFunctions
90{
91 ShellFunctions()
92 {
93 pSHGetFolderPath = NULL;
94 pSHGetSpecialFolderPath = NULL;
95 initialized = false;
96 }
97
98 SHGetFolderPath_t pSHGetFolderPath;
99 SHGetSpecialFolderPath_t pSHGetSpecialFolderPath;
100
101 bool initialized;
102};
103
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
106// harmless
4cd15b49 107ShellFunctions gs_shellFuncs;
40e8ee37
VZ
108
109// ----------------------------------------------------------------------------
110// private functions
111// ----------------------------------------------------------------------------
112
4cd15b49 113void ResolveShellFunctions()
40e8ee37 114{
64c288fa
JS
115#if wxUSE_DYNLIB_CLASS
116
40e8ee37 117 // start with the newest functions, fall back to the oldest ones
780d7317 118#ifdef __WXWINCE__
9a83f860 119 wxString shellDllName(wxT("coredll"));
780d7317 120#else
40e8ee37 121 // first check for SHGetFolderPath (shell32.dll 5.0)
9a83f860 122 wxString shellDllName(wxT("shell32"));
780d7317
JS
123#endif
124
125 wxDynamicLibrary dllShellFunctions( shellDllName );
126 if ( !dllShellFunctions.IsLoaded() )
40e8ee37 127 {
9a83f860 128 wxLogTrace(TRACE_MASK, wxT("Failed to load %s.dll"), shellDllName.c_str() );
40e8ee37
VZ
129 }
130
780d7317
JS
131 // don't give errors if the functions are unavailable, we're ready to deal
132 // with this
133 wxLogNull noLog;
134
40e8ee37 135#if wxUSE_UNICODE
780d7317
JS
136 #ifdef __WXWINCE__
137 static const wchar_t UNICODE_SUFFIX = L''; // WinCE SH functions don't seem to have 'W'
138 #else
139 static const wchar_t UNICODE_SUFFIX = L'W';
140 #endif
40e8ee37
VZ
141#else // !Unicode
142 static const char UNICODE_SUFFIX = 'A';
143#endif // Unicode/!Unicode
144
9a83f860 145 wxString funcname(wxT("SHGetFolderPath"));
40e8ee37 146 gs_shellFuncs.pSHGetFolderPath =
780d7317 147 (SHGetFolderPath_t)dllShellFunctions.GetSymbol(funcname + UNICODE_SUFFIX);
40e8ee37
VZ
148
149 // then for SHGetSpecialFolderPath (shell32.dll 4.71)
150 if ( !gs_shellFuncs.pSHGetFolderPath )
151 {
9a83f860 152 funcname = wxT("SHGetSpecialFolderPath");
40e8ee37 153 gs_shellFuncs.pSHGetSpecialFolderPath = (SHGetSpecialFolderPath_t)
780d7317 154 dllShellFunctions.GetSymbol(funcname + UNICODE_SUFFIX);
40e8ee37
VZ
155 }
156
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
159
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
162
163 gs_shellFuncs.initialized = true;
64c288fa 164#endif
40e8ee37
VZ
165}
166
4cd15b49
VZ
167} // anonymous namespace
168
40e8ee37
VZ
169// ============================================================================
170// wxStandardPaths implementation
171// ============================================================================
172
173// ----------------------------------------------------------------------------
174// private helpers
175// ----------------------------------------------------------------------------
176
177/* static */
178wxString wxStandardPaths::DoGetDirectory(int csidl)
179{
180 if ( !gs_shellFuncs.initialized )
181 ResolveShellFunctions();
182
183 wxString dir;
184 HRESULT hr = E_FAIL;
185
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 )
191 {
192 hr = gs_shellFuncs.pSHGetFolderPath
193 (
194 NULL, // parent window, not used
195 csidl,
196 NULL, // access token (current user)
197 SHGFP_TYPE_CURRENT, // current path, not just default value
198 wxStringBuffer(dir, MAX_PATH)
199 );
200
201 // somewhat incredibly, the error code in the Unicode version is
202 // different from the one in ASCII version for this function
203#if wxUSE_UNICODE
204 if ( hr == E_FAIL )
205#else
206 if ( hr == S_FALSE )
207#endif
208 {
209 // directory doesn't exist, maybe we can get its default value?
210 hr = gs_shellFuncs.pSHGetFolderPath
211 (
212 NULL,
213 csidl,
214 NULL,
215 SHGFP_TYPE_DEFAULT,
216 wxStringBuffer(dir, MAX_PATH)
217 );
218 }
219 }
220#endif // SHGetFolderPath
221
222#ifdef SHGetSpecialFolderPath
223 if ( FAILED(hr) && gs_shellFuncs.pSHGetSpecialFolderPath )
224 {
225 hr = gs_shellFuncs.pSHGetSpecialFolderPath
226 (
227 NULL, // parent window
228 wxStringBuffer(dir, MAX_PATH),
229 csidl,
230 FALSE // don't create if doesn't exist
231 );
232 }
233#endif // SHGetSpecialFolderPath
234
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)
238 if ( FAILED(hr) )
239 {
240 LPITEMIDLIST pidl;
241 hr = SHGetSpecialFolderLocation(NULL, csidl, &pidl);
242
243 if ( SUCCEEDED(hr) )
244 {
245 // creating this temp object has (nice) side effect of freeing pidl
246 dir = wxItemIdList(pidl).GetPath();
247 }
248 }
249
250 return dir;
251}
252
4cd15b49 253wxString wxStandardPaths::GetAppDir() const
adaa49a8 254{
4cd15b49 255 if ( m_appDir.empty() )
adaa49a8 256 {
4cd15b49 257 m_appDir = wxFileName(wxGetFullModuleName()).GetPath();
adaa49a8 258 }
adaa49a8 259
4cd15b49 260 return m_appDir;
adaa49a8
VZ
261}
262
17af82fb
VZ
263wxString wxStandardPaths::GetDocumentsDir() const
264{
265 return DoGetDirectory(CSIDL_PERSONAL);
266}
267
4cd15b49
VZ
268// ----------------------------------------------------------------------------
269// MSW-specific functions
270// ----------------------------------------------------------------------------
271
272void wxStandardPaths::IgnoreAppSubDir(const wxString& subdirPattern)
273{
274 wxFileName fn = wxFileName::DirName(GetAppDir());
275
276 if ( !fn.GetDirCount() )
277 {
278 // no last directory to ignore anyhow
279 return;
280 }
281
282 const wxString lastdir = fn.GetDirs().Last().Lower();
283 if ( lastdir.Matches(subdirPattern.Lower()) )
284 {
285 fn.RemoveLastDir();
286
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();
290 }
291}
292
293void wxStandardPaths::IgnoreAppBuildSubDirs()
294{
295 IgnoreAppSubDir("debug");
296 IgnoreAppSubDir("release");
297
298 wxString compilerPrefix;
299#ifdef __VISUALC__
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";
309#else
310 return;
311#endif
312
313 IgnoreAppSubDir(compilerPrefix + "_msw*");
314}
315
316void wxStandardPaths::DontIgnoreAppSubDir()
317{
318 // this will force the next call to GetAppDir() to use the program binary
319 // path as the application directory
320 m_appDir.clear();
321}
322
94aff795
VZ
323/* static */
324wxString wxStandardPaths::MSWGetShellDir(int csidl)
325{
326 return DoGetDirectory(csidl);
327}
328
40e8ee37
VZ
329// ----------------------------------------------------------------------------
330// public functions
331// ----------------------------------------------------------------------------
332
4cd15b49
VZ
333wxStandardPaths::wxStandardPaths()
334{
4cd15b49
VZ
335 // make it possible to run uninstalled application from the build directory
336 IgnoreAppBuildSubDirs();
337}
338
ac7ad70d
RR
339wxString wxStandardPaths::GetExecutablePath() const
340{
341 return wxGetFullModuleName();
342}
343
40e8ee37
VZ
344wxString wxStandardPaths::GetConfigDir() const
345{
2b147f2e 346 return AppendAppInfo(DoGetDirectory(CSIDL_COMMON_APPDATA));
40e8ee37
VZ
347}
348
349wxString wxStandardPaths::GetUserConfigDir() const
350{
351 return DoGetDirectory(CSIDL_APPDATA);
352}
353
354wxString wxStandardPaths::GetDataDir() const
355{
90537299
VZ
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
adaa49a8 358 return GetAppDir();
40e8ee37
VZ
359}
360
361wxString wxStandardPaths::GetUserDataDir() const
362{
2b147f2e 363 return AppendAppInfo(GetUserConfigDir());
40e8ee37
VZ
364}
365
366wxString wxStandardPaths::GetUserLocalDataDir() const
367{
2b147f2e 368 return AppendAppInfo(DoGetDirectory(CSIDL_LOCAL_APPDATA));
40e8ee37
VZ
369}
370
371wxString wxStandardPaths::GetPluginsDir() const
372{
adaa49a8
VZ
373 // there is no standard location for plugins, suppose they're in the same
374 // directory as the .exe
375 return GetAppDir();
40e8ee37
VZ
376}
377
40e8ee37
VZ
378// ============================================================================
379// wxStandardPathsWin16 implementation
380// ============================================================================
381
382wxString wxStandardPathsWin16::GetConfigDir() const
383{
384 // this is for compatibility with earlier wxFileConfig versions
385 // which used the Windows directory for the global files
386 wxString dir;
e2072525 387#ifndef __WXWINCE__
40e8ee37
VZ
388 if ( !::GetWindowsDirectory(wxStringBuffer(dir, MAX_PATH), MAX_PATH) )
389 {
9a83f860 390 wxLogLastError(wxT("GetWindowsDirectory"));
40e8ee37 391 }
e2072525 392#else
503602df 393 // TODO: use CSIDL_WINDOWS (eVC4, possibly not eVC3)
4fb9d560 394 dir = wxT("\\Windows");
e2072525 395#endif
40e8ee37
VZ
396
397 return dir;
398}
399
400wxString wxStandardPathsWin16::GetUserConfigDir() const
401{
402 // again, for wxFileConfig which uses $HOME for its user config file
403 return wxGetHomeDir();
404}
405
cd9a8d40 406#endif // wxUSE_STDPATHS