/ExtLibs/wxWidgets/src/common/filename.cpp
C++ | 3028 lines | 2121 code | 467 blank | 440 comment | 409 complexity | 96cbc28bd26a1f471022642ecc02e7de MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.0, BSD-3-Clause, LGPL-3.0, LGPL-2.1, AGPL-3.0
Large files files are truncated, but you can click here to view the full file
- /////////////////////////////////////////////////////////////////////////////
- // Name: src/common/filename.cpp
- // Purpose: wxFileName - encapsulates a file path
- // Author: Robert Roebling, Vadim Zeitlin
- // Modified by:
- // Created: 28.12.2000
- // Copyright: (c) 2000 Robert Roebling
- // Licence: wxWindows licence
- /////////////////////////////////////////////////////////////////////////////
- /*
- Here are brief descriptions of the filename formats supported by this class:
- wxPATH_UNIX: standard Unix format, used under Darwin as well, absolute file
- names have the form:
- /dir1/dir2/.../dirN/filename, "." and ".." stand for the
- current and parent directory respectively, "~" is parsed as the
- user HOME and "~username" as the HOME of that user
- wxPATH_DOS: DOS/Windows format, absolute file names have the form:
- drive:\dir1\dir2\...\dirN\filename.ext where drive is a single
- letter. "." and ".." as for Unix but no "~".
- There are also UNC names of the form \\share\fullpath and
- MSW unique volume names of the form \\?\Volume{GUID}\fullpath.
- The latter provide a uniform way to access a volume regardless of
- its current mount point, i.e. you can change a volume's mount
- point from D: to E:, or even remove it, and still be able to
- access it through its unique volume name. More on the subject can
- be found in MSDN's article "Naming a Volume" that is currently at
- http://msdn.microsoft.com/en-us/library/aa365248(VS.85).aspx.
- wxPATH_MAC: Mac OS 8/9 only, not used any longer, absolute file
- names have the form
- volume:dir1:...:dirN:filename
- and the relative file names are either
- :dir1:...:dirN:filename
- or just
- filename
- (although :filename works as well).
- Since the volume is just part of the file path, it is not
- treated like a separate entity as it is done under DOS and
- VMS, it is just treated as another dir.
- wxPATH_VMS: VMS native format, absolute file names have the form
- <device>:[dir1.dir2.dir3]file.txt
- or
- <device>:[000000.dir1.dir2.dir3]file.txt
- the <device> is the physical device (i.e. disk). 000000 is the
- root directory on the device which can be omitted.
- Note that VMS uses different separators unlike Unix:
- : always after the device. If the path does not contain : than
- the default (the device of the current directory) is assumed.
- [ start of directory specification
- . separator between directory and subdirectory
- ] between directory and file
- */
- // ============================================================================
- // declarations
- // ============================================================================
- // ----------------------------------------------------------------------------
- // headers
- // ----------------------------------------------------------------------------
- // For compilers that support precompilation, includes "wx.h".
- #include "wx/wxprec.h"
- #ifdef __BORLANDC__
- #pragma hdrstop
- #endif
- #ifndef WX_PRECOMP
- #ifdef __WINDOWS__
- #include "wx/msw/wrapwin.h" // For GetShort/LongPathName
- #endif
- #include "wx/dynarray.h"
- #include "wx/intl.h"
- #include "wx/log.h"
- #include "wx/utils.h"
- #include "wx/crt.h"
- #endif
- #include "wx/filename.h"
- #include "wx/private/filename.h"
- #include "wx/tokenzr.h"
- #include "wx/config.h" // for wxExpandEnvVars
- #include "wx/dynlib.h"
- #include "wx/dir.h"
- #include "wx/longlong.h"
- #if defined(__WIN32__) && defined(__MINGW32__)
- #include "wx/msw/gccpriv.h"
- #endif
- #ifdef __WINDOWS__
- #include "wx/msw/private.h"
- #include <shlobj.h> // for CLSID_ShellLink
- #include "wx/msw/missing.h"
- #endif
- #if defined(__WXMAC__)
- #include "wx/osx/private.h" // includes mac headers
- #endif
- // utime() is POSIX so should normally be available on all Unices
- #ifdef __UNIX_LIKE__
- #include <sys/types.h>
- #include <utime.h>
- #include <sys/stat.h>
- #include <unistd.h>
- #endif
- #ifdef __DJGPP__
- #include <unistd.h>
- #endif
- #ifdef __WATCOMC__
- #include <io.h>
- #include <sys/utime.h>
- #include <sys/stat.h>
- #endif
- #ifdef __VISAGECPP__
- #ifndef MAX_PATH
- #define MAX_PATH 256
- #endif
- #endif
- #ifdef __EMX__
- #include <os2.h>
- #define MAX_PATH _MAX_PATH
- #endif
- #ifndef S_ISREG
- #define S_ISREG(mode) ((mode) & S_IFREG)
- #endif
- #ifndef S_ISDIR
- #define S_ISDIR(mode) ((mode) & S_IFDIR)
- #endif
- #if wxUSE_LONGLONG
- extern const wxULongLong wxInvalidSize = (unsigned)-1;
- #endif // wxUSE_LONGLONG
- namespace
- {
- // ----------------------------------------------------------------------------
- // private classes
- // ----------------------------------------------------------------------------
- // small helper class which opens and closes the file - we use it just to get
- // a file handle for the given file name to pass it to some Win32 API function
- #if defined(__WIN32__) && !defined(__WXMICROWIN__)
- class wxFileHandle
- {
- public:
- enum OpenMode
- {
- ReadAttr,
- WriteAttr
- };
- wxFileHandle(const wxString& filename, OpenMode mode, int flags = 0)
- {
- // be careful and use FILE_{READ,WRITE}_ATTRIBUTES here instead of the
- // usual GENERIC_{READ,WRITE} as we don't want the file access time to
- // be changed when we open it because this class is used for setting
- // access time (see #10567)
- m_hFile = ::CreateFile
- (
- filename.t_str(), // name
- mode == ReadAttr ? FILE_READ_ATTRIBUTES // access mask
- : FILE_WRITE_ATTRIBUTES,
- FILE_SHARE_READ | // sharing mode
- FILE_SHARE_WRITE, // (allow everything)
- NULL, // no secutity attr
- OPEN_EXISTING, // creation disposition
- flags, // flags
- NULL // no template file
- );
- if ( m_hFile == INVALID_HANDLE_VALUE )
- {
- if ( mode == ReadAttr )
- {
- wxLogSysError(_("Failed to open '%s' for reading"),
- filename.c_str());
- }
- else
- {
- wxLogSysError(_("Failed to open '%s' for writing"),
- filename.c_str());
- }
- }
- }
- ~wxFileHandle()
- {
- if ( m_hFile != INVALID_HANDLE_VALUE )
- {
- if ( !::CloseHandle(m_hFile) )
- {
- wxLogSysError(_("Failed to close file handle"));
- }
- }
- }
- // return true only if the file could be opened successfully
- bool IsOk() const { return m_hFile != INVALID_HANDLE_VALUE; }
- // get the handle
- operator HANDLE() const { return m_hFile; }
- private:
- HANDLE m_hFile;
- };
- #endif // __WIN32__
- // ----------------------------------------------------------------------------
- // private functions
- // ----------------------------------------------------------------------------
- #if wxUSE_DATETIME && defined(__WIN32__) && !defined(__WXMICROWIN__)
- // Convert between wxDateTime and FILETIME which is a 64-bit value representing
- // the number of 100-nanosecond intervals since January 1, 1601 UTC.
- //
- // This is the offset between FILETIME epoch and the Unix/wxDateTime Epoch.
- static wxInt64 EPOCH_OFFSET_IN_MSEC = wxLL(11644473600000);
- static void ConvertFileTimeToWx(wxDateTime *dt, const FILETIME &ft)
- {
- wxLongLong t(ft.dwHighDateTime, ft.dwLowDateTime);
- t /= 10000; // Convert hundreds of nanoseconds to milliseconds.
- t -= EPOCH_OFFSET_IN_MSEC;
- *dt = wxDateTime(t);
- }
- static void ConvertWxToFileTime(FILETIME *ft, const wxDateTime& dt)
- {
- // Undo the conversions above.
- wxLongLong t(dt.GetValue());
- t += EPOCH_OFFSET_IN_MSEC;
- t *= 10000;
- ft->dwHighDateTime = t.GetHi();
- ft->dwLowDateTime = t.GetLo();
- }
- #endif // wxUSE_DATETIME && __WIN32__
- // return a string with the volume par
- static wxString wxGetVolumeString(const wxString& volume, wxPathFormat format)
- {
- wxString path;
- if ( !volume.empty() )
- {
- format = wxFileName::GetFormat(format);
- // Special Windows UNC paths hack, part 2: undo what we did in
- // SplitPath() and make an UNC path if we have a drive which is not a
- // single letter (hopefully the network shares can't be one letter only
- // although I didn't find any authoritative docs on this)
- if ( format == wxPATH_DOS && volume.length() > 1 )
- {
- // We also have to check for Windows unique volume names here and
- // return it with '\\?\' prepended to it
- if ( wxFileName::IsMSWUniqueVolumeNamePath("\\\\?\\" + volume + "\\",
- format) )
- {
- path << "\\\\?\\" << volume;
- }
- else
- {
- // it must be a UNC path
- path << wxFILE_SEP_PATH_DOS << wxFILE_SEP_PATH_DOS << volume;
- }
- }
- else if ( format == wxPATH_DOS || format == wxPATH_VMS )
- {
- path << volume << wxFileName::GetVolumeSeparator(format);
- }
- // else ignore
- }
- return path;
- }
- // return true if the character is a DOS path separator i.e. either a slash or
- // a backslash
- inline bool IsDOSPathSep(wxUniChar ch)
- {
- return ch == wxFILE_SEP_PATH_DOS || ch == wxFILE_SEP_PATH_UNIX;
- }
- // return true if the format used is the DOS/Windows one and the string looks
- // like a UNC path
- static bool IsUNCPath(const wxString& path, wxPathFormat format)
- {
- return format == wxPATH_DOS &&
- path.length() >= 4 && // "\\a" can't be a UNC path
- IsDOSPathSep(path[0u]) &&
- IsDOSPathSep(path[1u]) &&
- !IsDOSPathSep(path[2u]);
- }
- // Under Unix-ish systems (basically everything except Windows but we can't
- // just test for non-__WIN32__ because Cygwin defines it, yet we want to use
- // lstat() under it, so test for all the rest explicitly) we may work either
- // with the file itself or its target if it's a symbolic link and we should
- // dereference it, as determined by wxFileName::ShouldFollowLink() and the
- // absence of the wxFILE_EXISTS_NO_FOLLOW flag. StatAny() can be used to stat
- // the appropriate file with an extra twist that it also works when there is no
- // wxFileName object at all, as is the case in static methods.
- #if defined(__UNIX_LIKE__) || defined(__WXMAC__) || defined(__OS2__) || (defined(__DOS__) && defined(__WATCOMC__))
- #define wxHAVE_LSTAT
- #endif
- #ifdef wxHAVE_LSTAT
- // Private implementation, don't call directly, use one of the overloads below.
- bool DoStatAny(wxStructStat& st, wxString path, bool dereference)
- {
- // We need to remove any trailing slashes from the path because they could
- // interfere with the symlink following decision: even if we use lstat(),
- // it would still follow the symlink if we pass it a path with a slash at
- // the end because the symlink resolution would happen while following the
- // path and not for the last path element itself.
- while ( wxEndsWithPathSeparator(path) )
- {
- const size_t posLast = path.length() - 1;
- if ( !posLast )
- {
- // Don't turn "/" into empty string.
- break;
- }
- path.erase(posLast);
- }
- int ret = dereference ? wxStat(path, &st) : wxLstat(path, &st);
- return ret == 0;
- }
- // Overloads to use for a case when we don't have wxFileName object and when we
- // do have one.
- inline
- bool StatAny(wxStructStat& st, const wxString& path, int flags)
- {
- return DoStatAny(st, path, !(flags & wxFILE_EXISTS_NO_FOLLOW));
- }
- inline
- bool StatAny(wxStructStat& st, const wxFileName& fn)
- {
- return DoStatAny(st, fn.GetFullPath(), fn.ShouldFollowLink());
- }
- #endif // wxHAVE_LSTAT
- // ----------------------------------------------------------------------------
- // private constants
- // ----------------------------------------------------------------------------
- // length of \\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\ string
- static const size_t wxMSWUniqueVolumePrefixLength = 49;
- } // anonymous namespace
- // ============================================================================
- // implementation
- // ============================================================================
- // ----------------------------------------------------------------------------
- // wxFileName construction
- // ----------------------------------------------------------------------------
- void wxFileName::Assign( const wxFileName &filepath )
- {
- m_volume = filepath.GetVolume();
- m_dirs = filepath.GetDirs();
- m_name = filepath.GetName();
- m_ext = filepath.GetExt();
- m_relative = filepath.m_relative;
- m_hasExt = filepath.m_hasExt;
- m_dontFollowLinks = filepath.m_dontFollowLinks;
- }
- void wxFileName::Assign(const wxString& volume,
- const wxString& path,
- const wxString& name,
- const wxString& ext,
- bool hasExt,
- wxPathFormat format)
- {
- // we should ignore paths which look like UNC shares because we already
- // have the volume here and the UNC notation (\\server\path) is only valid
- // for paths which don't start with a volume, so prevent SetPath() from
- // recognizing "\\foo\bar" in "c:\\foo\bar" as an UNC path
- //
- // note also that this is a rather ugly way to do what we want (passing
- // some kind of flag telling to ignore UNC paths to SetPath() would be
- // better) but this is the safest thing to do to avoid breaking backwards
- // compatibility in 2.8
- if ( IsUNCPath(path, format) )
- {
- // remove one of the 2 leading backslashes to ensure that it's not
- // recognized as an UNC path by SetPath()
- wxString pathNonUNC(path, 1, wxString::npos);
- SetPath(pathNonUNC, format);
- }
- else // no UNC complications
- {
- SetPath(path, format);
- }
- m_volume = volume;
- m_ext = ext;
- m_name = name;
- m_hasExt = hasExt;
- }
- void wxFileName::SetPath( const wxString& pathOrig, wxPathFormat format )
- {
- m_dirs.Clear();
- if ( pathOrig.empty() )
- {
- // no path at all
- m_relative = true;
- return;
- }
- format = GetFormat( format );
- // 0) deal with possible volume part first
- wxString volume,
- path;
- SplitVolume(pathOrig, &volume, &path, format);
- if ( !volume.empty() )
- {
- m_relative = false;
- SetVolume(volume);
- }
- // 1) Determine if the path is relative or absolute.
- if ( path.empty() )
- {
- // we had only the volume
- return;
- }
- wxChar leadingChar = path[0u];
- switch (format)
- {
- case wxPATH_MAC:
- m_relative = leadingChar == wxT(':');
- // We then remove a leading ":". The reason is in our
- // storage form for relative paths:
- // ":dir:file.txt" actually means "./dir/file.txt" in
- // DOS notation and should get stored as
- // (relative) (dir) (file.txt)
- // "::dir:file.txt" actually means "../dir/file.txt"
- // stored as (relative) (..) (dir) (file.txt)
- // This is important only for the Mac as an empty dir
- // actually means <UP>, whereas under DOS, double
- // slashes can be ignored: "\\\\" is the same as "\\".
- if (m_relative)
- path.erase( 0, 1 );
- break;
- case wxPATH_VMS:
- // TODO: what is the relative path format here?
- m_relative = false;
- break;
- default:
- wxFAIL_MSG( wxT("Unknown path format") );
- // !! Fall through !!
- case wxPATH_UNIX:
- m_relative = leadingChar != wxT('/');
- break;
- case wxPATH_DOS:
- m_relative = !IsPathSeparator(leadingChar, format);
- break;
- }
- // 2) Break up the path into its members. If the original path
- // was just "/" or "\\", m_dirs will be empty. We know from
- // the m_relative field, if this means "nothing" or "root dir".
- wxStringTokenizer tn( path, GetPathSeparators(format) );
- while ( tn.HasMoreTokens() )
- {
- wxString token = tn.GetNextToken();
- // Remove empty token under DOS and Unix, interpret them
- // as .. under Mac.
- if (token.empty())
- {
- if (format == wxPATH_MAC)
- m_dirs.Add( wxT("..") );
- // else ignore
- }
- else
- {
- m_dirs.Add( token );
- }
- }
- }
- void wxFileName::Assign(const wxString& fullpath,
- wxPathFormat format)
- {
- wxString volume, path, name, ext;
- bool hasExt;
- SplitPath(fullpath, &volume, &path, &name, &ext, &hasExt, format);
- Assign(volume, path, name, ext, hasExt, format);
- }
- void wxFileName::Assign(const wxString& fullpathOrig,
- const wxString& fullname,
- wxPathFormat format)
- {
- // always recognize fullpath as directory, even if it doesn't end with a
- // slash
- wxString fullpath = fullpathOrig;
- if ( !fullpath.empty() && !wxEndsWithPathSeparator(fullpath) )
- {
- fullpath += GetPathSeparator(format);
- }
- wxString volume, path, name, ext;
- bool hasExt;
- // do some consistency checks: the name should be really just the filename
- // and the path should be really just a path
- wxString volDummy, pathDummy, nameDummy, extDummy;
- SplitPath(fullname, &volDummy, &pathDummy, &name, &ext, &hasExt, format);
- wxASSERT_MSG( volDummy.empty() && pathDummy.empty(),
- wxT("the file name shouldn't contain the path") );
- SplitPath(fullpath, &volume, &path, &nameDummy, &extDummy, format);
- #ifndef __VMS
- // This test makes no sense on an OpenVMS system.
- wxASSERT_MSG( nameDummy.empty() && extDummy.empty(),
- wxT("the path shouldn't contain file name nor extension") );
- #endif
- Assign(volume, path, name, ext, hasExt, format);
- }
- void wxFileName::Assign(const wxString& pathOrig,
- const wxString& name,
- const wxString& ext,
- wxPathFormat format)
- {
- wxString volume,
- path;
- SplitVolume(pathOrig, &volume, &path, format);
- Assign(volume, path, name, ext, format);
- }
- void wxFileName::AssignDir(const wxString& dir, wxPathFormat format)
- {
- Assign(dir, wxEmptyString, format);
- }
- void wxFileName::Clear()
- {
- m_dirs.clear();
- m_volume.clear();
- m_name.clear();
- m_ext.clear();
- // we don't have any absolute path for now
- m_relative = true;
- // nor any extension
- m_hasExt = false;
- // follow symlinks by default
- m_dontFollowLinks = false;
- }
- /* static */
- wxFileName wxFileName::FileName(const wxString& file, wxPathFormat format)
- {
- return wxFileName(file, format);
- }
- /* static */
- wxFileName wxFileName::DirName(const wxString& dir, wxPathFormat format)
- {
- wxFileName fn;
- fn.AssignDir(dir, format);
- return fn;
- }
- // ----------------------------------------------------------------------------
- // existence tests
- // ----------------------------------------------------------------------------
- namespace
- {
- #if defined(__WINDOWS__) && !defined(__WXMICROWIN__)
- void RemoveTrailingSeparatorsFromPath(wxString& strPath)
- {
- // Windows fails to find directory named "c:\dir\" even if "c:\dir" exists,
- // so remove all trailing backslashes from the path - but don't do this for
- // the paths "d:\" (which are different from "d:"), for just "\" or for
- // windows unique volume names ("\\?\Volume{GUID}\")
- while ( wxEndsWithPathSeparator( strPath ) )
- {
- size_t len = strPath.length();
- if ( len == 1 || (len == 3 && strPath[len - 2] == wxT(':')) ||
- (len == wxMSWUniqueVolumePrefixLength &&
- wxFileName::IsMSWUniqueVolumeNamePath(strPath)))
- {
- break;
- }
- strPath.Truncate(len - 1);
- }
- }
- #endif // __WINDOWS__ || __OS2__
- bool
- wxFileSystemObjectExists(const wxString& path, int flags)
- {
- // Should the existence of file/directory with this name be accepted, i.e.
- // result in the true return value from this function?
- const bool acceptFile = (flags & wxFILE_EXISTS_REGULAR) != 0;
- const bool acceptDir = (flags & wxFILE_EXISTS_DIR) != 0;
- wxString strPath(path);
- #if defined(__WINDOWS__) && !defined(__WXMICROWIN__)
- if ( acceptDir )
- {
- // Ensure that the path doesn't have any trailing separators when
- // checking for directories.
- RemoveTrailingSeparatorsFromPath(strPath);
- }
- // we must use GetFileAttributes() instead of the ANSI C functions because
- // it can cope with network (UNC) paths unlike them
- DWORD ret = ::GetFileAttributes(strPath.t_str());
- if ( ret == INVALID_FILE_ATTRIBUTES )
- return false;
- if ( ret & FILE_ATTRIBUTE_DIRECTORY )
- return acceptDir;
- // Anything else must be a file (perhaps we should check for
- // FILE_ATTRIBUTE_REPARSE_POINT?)
- return acceptFile;
- #elif defined(__OS2__)
- if ( acceptDir )
- {
- // OS/2 can't handle "d:", it wants either "d:\" or "d:."
- if (strPath.length() == 2 && strPath[1u] == wxT(':'))
- strPath << wxT('.');
- }
- FILESTATUS3 Info = {{0}};
- APIRET rc = ::DosQueryPathInfo((PSZ)(WXSTRINGCAST strPath), FIL_STANDARD,
- (void*) &Info, sizeof(FILESTATUS3));
- if ( rc == NO_ERROR )
- {
- if ( Info.attrFile & FILE_DIRECTORY )
- return acceptDir;
- else
- return acceptFile;
- }
- // We consider that the path must exist if we get a sharing violation for
- // it but we don't know what is it in this case.
- if ( rc == ERROR_SHARING_VIOLATION )
- return flags & wxFILE_EXISTS_ANY;
- // Any other error (usually ERROR_PATH_NOT_FOUND), means there is nothing
- // there.
- return false;
- #else // Non-MSW, non-OS/2
- wxStructStat st;
- if ( !StatAny(st, strPath, flags) )
- return false;
- if ( S_ISREG(st.st_mode) )
- return acceptFile;
- if ( S_ISDIR(st.st_mode) )
- return acceptDir;
- if ( S_ISLNK(st.st_mode) )
- {
- // Take care to not test for "!= 0" here as this would erroneously
- // return true if only wxFILE_EXISTS_NO_FOLLOW, which is part of
- // wxFILE_EXISTS_SYMLINK, is set too.
- return (flags & wxFILE_EXISTS_SYMLINK) == wxFILE_EXISTS_SYMLINK;
- }
- if ( S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) )
- return (flags & wxFILE_EXISTS_DEVICE) != 0;
- if ( S_ISFIFO(st.st_mode) )
- return (flags & wxFILE_EXISTS_FIFO) != 0;
- if ( S_ISSOCK(st.st_mode) )
- return (flags & wxFILE_EXISTS_SOCKET) != 0;
- return flags & wxFILE_EXISTS_ANY;
- #endif // Platforms
- }
- } // anonymous namespace
- bool wxFileName::FileExists() const
- {
- int flags = wxFILE_EXISTS_REGULAR;
- if ( !ShouldFollowLink() )
- flags |= wxFILE_EXISTS_NO_FOLLOW;
- return wxFileSystemObjectExists(GetFullPath(), flags);
- }
- /* static */
- bool wxFileName::FileExists( const wxString &filePath )
- {
- return wxFileSystemObjectExists(filePath, wxFILE_EXISTS_REGULAR);
- }
- bool wxFileName::DirExists() const
- {
- int flags = wxFILE_EXISTS_DIR;
- if ( !ShouldFollowLink() )
- flags |= wxFILE_EXISTS_NO_FOLLOW;
- return Exists(GetPath(), flags);
- }
- /* static */
- bool wxFileName::DirExists( const wxString &dirPath )
- {
- return wxFileSystemObjectExists(dirPath, wxFILE_EXISTS_DIR);
- }
- bool wxFileName::Exists(int flags) const
- {
- // Notice that wxFILE_EXISTS_NO_FOLLOW may be specified in the flags even
- // if our DontFollowLink() hadn't been called and we do honour it then. But
- // if the user took the care of calling DontFollowLink(), it is always
- // taken into account.
- if ( !ShouldFollowLink() )
- flags |= wxFILE_EXISTS_NO_FOLLOW;
- return wxFileSystemObjectExists(GetFullPath(), flags);
- }
- /* static */
- bool wxFileName::Exists(const wxString& path, int flags)
- {
- return wxFileSystemObjectExists(path, flags);
- }
- // ----------------------------------------------------------------------------
- // CWD and HOME stuff
- // ----------------------------------------------------------------------------
- void wxFileName::AssignCwd(const wxString& volume)
- {
- AssignDir(wxFileName::GetCwd(volume));
- }
- /* static */
- wxString wxFileName::GetCwd(const wxString& volume)
- {
- // if we have the volume, we must get the current directory on this drive
- // and to do this we have to chdir to this volume - at least under Windows,
- // I don't know how to get the current drive on another volume elsewhere
- // (TODO)
- wxString cwdOld;
- if ( !volume.empty() )
- {
- cwdOld = wxGetCwd();
- SetCwd(volume + GetVolumeSeparator());
- }
- wxString cwd = ::wxGetCwd();
- if ( !volume.empty() )
- {
- SetCwd(cwdOld);
- }
- return cwd;
- }
- bool wxFileName::SetCwd() const
- {
- return wxFileName::SetCwd( GetPath() );
- }
- bool wxFileName::SetCwd( const wxString &cwd )
- {
- return ::wxSetWorkingDirectory( cwd );
- }
- void wxFileName::AssignHomeDir()
- {
- AssignDir(wxFileName::GetHomeDir());
- }
- wxString wxFileName::GetHomeDir()
- {
- return ::wxGetHomeDir();
- }
- // ----------------------------------------------------------------------------
- // CreateTempFileName
- // ----------------------------------------------------------------------------
- #if wxUSE_FILE || wxUSE_FFILE
- #if !defined wx_fdopen && defined HAVE_FDOPEN
- #define wx_fdopen fdopen
- #endif
- // NB: GetTempFileName() under Windows creates the file, so using
- // O_EXCL there would fail
- #ifdef __WINDOWS__
- #define wxOPEN_EXCL 0
- #else
- #define wxOPEN_EXCL O_EXCL
- #endif
- #ifdef wxOpenOSFHandle
- #define WX_HAVE_DELETE_ON_CLOSE
- // On Windows create a file with the FILE_FLAGS_DELETE_ON_CLOSE flags.
- //
- static int wxOpenWithDeleteOnClose(const wxString& filename)
- {
- DWORD access = GENERIC_READ | GENERIC_WRITE;
- DWORD disposition = OPEN_ALWAYS;
- DWORD attributes = FILE_ATTRIBUTE_TEMPORARY |
- FILE_FLAG_DELETE_ON_CLOSE;
- HANDLE h = ::CreateFile(filename.t_str(), access, 0, NULL,
- disposition, attributes, NULL);
- return wxOpenOSFHandle(h, wxO_BINARY);
- }
- #endif // wxOpenOSFHandle
- // Helper to open the file
- //
- static int wxTempOpen(const wxString& path, bool *deleteOnClose)
- {
- #ifdef WX_HAVE_DELETE_ON_CLOSE
- if (*deleteOnClose)
- return wxOpenWithDeleteOnClose(path);
- #endif
- *deleteOnClose = false;
- return wxOpen(path, wxO_BINARY | O_RDWR | O_CREAT | wxOPEN_EXCL, 0600);
- }
- #if wxUSE_FFILE
- // Helper to open the file and attach it to the wxFFile
- //
- static bool wxTempOpen(wxFFile *file, const wxString& path, bool *deleteOnClose)
- {
- #ifndef wx_fdopen
- *deleteOnClose = false;
- return file->Open(path, wxT("w+b"));
- #else // wx_fdopen
- int fd = wxTempOpen(path, deleteOnClose);
- if (fd == -1)
- return false;
- file->Attach(wx_fdopen(fd, "w+b"), path);
- return file->IsOpened();
- #endif // wx_fdopen
- }
- #endif // wxUSE_FFILE
- #if !wxUSE_FILE
- #define WXFILEARGS(x, y) y
- #elif !wxUSE_FFILE
- #define WXFILEARGS(x, y) x
- #else
- #define WXFILEARGS(x, y) x, y
- #endif
- // Implementation of wxFileName::CreateTempFileName().
- //
- static wxString wxCreateTempImpl(
- const wxString& prefix,
- WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp),
- bool *deleteOnClose = NULL)
- {
- #if wxUSE_FILE && wxUSE_FFILE
- wxASSERT(fileTemp == NULL || ffileTemp == NULL);
- #endif
- wxString path, dir, name;
- bool wantDeleteOnClose = false;
- if (deleteOnClose)
- {
- // set the result to false initially
- wantDeleteOnClose = *deleteOnClose;
- *deleteOnClose = false;
- }
- else
- {
- // easier if it alwasys points to something
- deleteOnClose = &wantDeleteOnClose;
- }
- // use the directory specified by the prefix
- wxFileName::SplitPath(prefix, &dir, &name, NULL /* extension */);
- if (dir.empty())
- {
- dir = wxFileName::GetTempDir();
- }
- #if defined(__WXWINCE__)
- path = dir + wxT("\\") + name;
- int i = 1;
- while (wxFileName::FileExists(path))
- {
- path = dir + wxT("\\") + name ;
- path << i;
- i ++;
- }
- #elif defined(__WINDOWS__) && !defined(__WXMICROWIN__)
- if (!::GetTempFileName(dir.t_str(), name.t_str(), 0,
- wxStringBuffer(path, MAX_PATH + 1)))
- {
- wxLogLastError(wxT("GetTempFileName"));
- path.clear();
- }
- #else // !Windows
- path = dir;
- if ( !wxEndsWithPathSeparator(dir) &&
- (name.empty() || !wxIsPathSeparator(name[0u])) )
- {
- path += wxFILE_SEP_PATH;
- }
- path += name;
- #if defined(HAVE_MKSTEMP)
- // scratch space for mkstemp()
- path += wxT("XXXXXX");
- // we need to copy the path to the buffer in which mkstemp() can modify it
- wxCharBuffer buf(path.fn_str());
- // cast is safe because the string length doesn't change
- int fdTemp = mkstemp( (char*)(const char*) buf );
- if ( fdTemp == -1 )
- {
- // this might be not necessary as mkstemp() on most systems should have
- // already done it but it doesn't hurt neither...
- path.clear();
- }
- else // mkstemp() succeeded
- {
- path = wxConvFile.cMB2WX( (const char*) buf );
- #if wxUSE_FILE
- // avoid leaking the fd
- if ( fileTemp )
- {
- fileTemp->Attach(fdTemp);
- }
- else
- #endif
- #if wxUSE_FFILE
- if ( ffileTemp )
- {
- #ifdef wx_fdopen
- ffileTemp->Attach(wx_fdopen(fdTemp, "r+b"), path);
- #else
- ffileTemp->Open(path, wxT("r+b"));
- close(fdTemp);
- #endif
- }
- else
- #endif
- {
- close(fdTemp);
- }
- }
- #else // !HAVE_MKSTEMP
- #ifdef HAVE_MKTEMP
- // same as above
- path += wxT("XXXXXX");
- wxCharBuffer buf = wxConvFile.cWX2MB( path );
- if ( !mktemp( (char*)(const char*) buf ) )
- {
- path.clear();
- }
- else
- {
- path = wxConvFile.cMB2WX( (const char*) buf );
- }
- #else // !HAVE_MKTEMP (includes __DOS__)
- // generate the unique file name ourselves
- #if !defined(__DOS__)
- path << (unsigned int)getpid();
- #endif
- wxString pathTry;
- static const size_t numTries = 1000;
- for ( size_t n = 0; n < numTries; n++ )
- {
- // 3 hex digits is enough for numTries == 1000 < 4096
- pathTry = path + wxString::Format(wxT("%.03x"), (unsigned int) n);
- if ( !wxFileName::FileExists(pathTry) )
- {
- break;
- }
- pathTry.clear();
- }
- path = pathTry;
- #endif // HAVE_MKTEMP/!HAVE_MKTEMP
- #endif // HAVE_MKSTEMP/!HAVE_MKSTEMP
- #endif // Windows/!Windows
- if ( path.empty() )
- {
- wxLogSysError(_("Failed to create a temporary file name"));
- }
- else
- {
- bool ok = true;
- // open the file - of course, there is a race condition here, this is
- // why we always prefer using mkstemp()...
- #if wxUSE_FILE
- if ( fileTemp && !fileTemp->IsOpened() )
- {
- *deleteOnClose = wantDeleteOnClose;
- int fd = wxTempOpen(path, deleteOnClose);
- if (fd != -1)
- fileTemp->Attach(fd);
- else
- ok = false;
- }
- #endif
- #if wxUSE_FFILE
- if ( ffileTemp && !ffileTemp->IsOpened() )
- {
- *deleteOnClose = wantDeleteOnClose;
- ok = wxTempOpen(ffileTemp, path, deleteOnClose);
- }
- #endif
- if ( !ok )
- {
- // FIXME: If !ok here should we loop and try again with another
- // file name? That is the standard recourse if open(O_EXCL)
- // fails, though of course it should be protected against
- // possible infinite looping too.
- wxLogError(_("Failed to open temporary file."));
- path.clear();
- }
- }
- return path;
- }
- static bool wxCreateTempImpl(
- const wxString& prefix,
- WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp),
- wxString *name)
- {
- bool deleteOnClose = true;
- *name = wxCreateTempImpl(prefix,
- WXFILEARGS(fileTemp, ffileTemp),
- &deleteOnClose);
- bool ok = !name->empty();
- if (deleteOnClose)
- name->clear();
- #ifdef __UNIX__
- else if (ok && wxRemoveFile(*name))
- name->clear();
- #endif
- return ok;
- }
- static void wxAssignTempImpl(
- wxFileName *fn,
- const wxString& prefix,
- WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp))
- {
- wxString tempname;
- tempname = wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, ffileTemp));
- if ( tempname.empty() )
- {
- // error, failed to get temp file name
- fn->Clear();
- }
- else // ok
- {
- fn->Assign(tempname);
- }
- }
- void wxFileName::AssignTempFileName(const wxString& prefix)
- {
- wxAssignTempImpl(this, prefix, WXFILEARGS(NULL, NULL));
- }
- /* static */
- wxString wxFileName::CreateTempFileName(const wxString& prefix)
- {
- return wxCreateTempImpl(prefix, WXFILEARGS(NULL, NULL));
- }
- #endif // wxUSE_FILE || wxUSE_FFILE
- #if wxUSE_FILE
- wxString wxCreateTempFileName(const wxString& prefix,
- wxFile *fileTemp,
- bool *deleteOnClose)
- {
- return wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, NULL), deleteOnClose);
- }
- bool wxCreateTempFile(const wxString& prefix,
- wxFile *fileTemp,
- wxString *name)
- {
- return wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, NULL), name);
- }
- void wxFileName::AssignTempFileName(const wxString& prefix, wxFile *fileTemp)
- {
- wxAssignTempImpl(this, prefix, WXFILEARGS(fileTemp, NULL));
- }
- /* static */
- wxString
- wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp)
- {
- return wxCreateTempFileName(prefix, fileTemp);
- }
- #endif // wxUSE_FILE
- #if wxUSE_FFILE
- wxString wxCreateTempFileName(const wxString& prefix,
- wxFFile *fileTemp,
- bool *deleteOnClose)
- {
- return wxCreateTempImpl(prefix, WXFILEARGS(NULL, fileTemp), deleteOnClose);
- }
- bool wxCreateTempFile(const wxString& prefix,
- wxFFile *fileTemp,
- wxString *name)
- {
- return wxCreateTempImpl(prefix, WXFILEARGS(NULL, fileTemp), name);
- }
- void wxFileName::AssignTempFileName(const wxString& prefix, wxFFile *fileTemp)
- {
- wxAssignTempImpl(this, prefix, WXFILEARGS(NULL, fileTemp));
- }
- /* static */
- wxString
- wxFileName::CreateTempFileName(const wxString& prefix, wxFFile *fileTemp)
- {
- return wxCreateTempFileName(prefix, fileTemp);
- }
- #endif // wxUSE_FFILE
- // ----------------------------------------------------------------------------
- // directory operations
- // ----------------------------------------------------------------------------
- // helper of GetTempDir(): check if the given directory exists and return it if
- // it does or an empty string otherwise
- namespace
- {
- wxString CheckIfDirExists(const wxString& dir)
- {
- return wxFileName::DirExists(dir) ? dir : wxString();
- }
- } // anonymous namespace
- wxString wxFileName::GetTempDir()
- {
- // first try getting it from environment: this allows overriding the values
- // used by default if the user wants to create temporary files in another
- // directory
- wxString dir = CheckIfDirExists(wxGetenv("TMPDIR"));
- if ( dir.empty() )
- {
- dir = CheckIfDirExists(wxGetenv("TMP"));
- if ( dir.empty() )
- dir = CheckIfDirExists(wxGetenv("TEMP"));
- }
- // if no environment variables are set, use the system default
- if ( dir.empty() )
- {
- #if defined(__WXWINCE__)
- dir = CheckIfDirExists(wxT("\\temp"));
- #elif defined(__WINDOWS__) && !defined(__WXMICROWIN__)
- if ( !::GetTempPath(MAX_PATH, wxStringBuffer(dir, MAX_PATH + 1)) )
- {
- wxLogLastError(wxT("GetTempPath"));
- }
- #elif defined(__WXMAC__) && wxOSX_USE_CARBON
- dir = wxMacFindFolderNoSeparator(short(kOnSystemDisk), kTemporaryFolderType, kCreateFolder);
- #endif // systems with native way
- }
- else // we got directory from an environment variable
- {
- // remove any trailing path separators, we don't want to ever return
- // them from this function for consistency
- const size_t lastNonSep = dir.find_last_not_of(GetPathSeparators());
- if ( lastNonSep == wxString::npos )
- {
- // the string consists entirely of separators, leave only one
- dir = GetPathSeparator();
- }
- else
- {
- dir.erase(lastNonSep + 1);
- }
- }
- // fall back to hard coded value
- if ( dir.empty() )
- {
- #ifdef __UNIX_LIKE__
- dir = CheckIfDirExists("/tmp");
- if ( dir.empty() )
- #endif // __UNIX_LIKE__
- dir = ".";
- }
- return dir;
- }
- bool wxFileName::Mkdir( int perm, int flags ) const
- {
- return wxFileName::Mkdir(GetPath(), perm, flags);
- }
- bool wxFileName::Mkdir( const wxString& dir, int perm, int flags )
- {
- if ( flags & wxPATH_MKDIR_FULL )
- {
- // split the path in components
- wxFileName filename;
- filename.AssignDir(dir);
- wxString currPath;
- if ( filename.HasVolume())
- {
- currPath << wxGetVolumeString(filename.GetVolume(), wxPATH_NATIVE);
- }
- wxArrayString dirs = filename.GetDirs();
- size_t count = dirs.GetCount();
- for ( size_t i = 0; i < count; i++ )
- {
- if ( i > 0 || filename.IsAbsolute() )
- currPath += wxFILE_SEP_PATH;
- currPath += dirs[i];
- if (!DirExists(currPath))
- {
- if (!wxMkdir(currPath, perm))
- {
- // no need to try creating further directories
- return false;
- }
- }
- }
- return true;
- }
- return ::wxMkdir( dir, perm );
- }
- bool wxFileName::Rmdir(int flags) const
- {
- return wxFileName::Rmdir( GetPath(), flags );
- }
- bool wxFileName::Rmdir(const wxString& dir, int flags)
- {
- #ifdef __WINDOWS__
- if ( flags & wxPATH_RMDIR_RECURSIVE )
- {
- // SHFileOperation needs double null termination string
- // but without separator at the end of the path
- wxString path(dir);
- if ( path.Last() == wxFILE_SEP_PATH )
- path.RemoveLast();
- path += wxT('\0');
- SHFILEOPSTRUCT fileop;
- wxZeroMemory(fileop);
- fileop.wFunc = FO_DELETE;
- fileop.pFrom = path.t_str();
- fileop.fFlags = FOF_SILENT | FOF_NOCONFIRMATION;
- #ifndef __WXWINCE__
- // FOF_NOERRORUI is not defined in WinCE
- fileop.fFlags |= FOF_NOERRORUI;
- #endif
- int ret = SHFileOperation(&fileop);
- if ( ret != 0 )
- {
- // SHFileOperation may return non-Win32 error codes, so the error
- // message can be incorrect
- wxLogApiError(wxT("SHFileOperation"), ret);
- return false;
- }
- return true;
- }
- else if ( flags & wxPATH_RMDIR_FULL )
- #else // !__WINDOWS__
- if ( flags != 0 ) // wxPATH_RMDIR_FULL or wxPATH_RMDIR_RECURSIVE
- #endif // !__WINDOWS__
- {
- #ifndef __WINDOWS__
- if ( flags & wxPATH_RMDIR_RECURSIVE )
- {
- // When deleting the tree recursively, we are supposed to delete
- // this directory itself even when it is a symlink -- but without
- // following it. Do it here as wxRmdir() would simply follow if
- // called for a symlink.
- if ( wxFileName::Exists(dir, wxFILE_EXISTS_SYMLINK) )
- {
- return wxRemoveFile(dir);
- }
- }
- #endif // !__WINDOWS__
- wxString path(dir);
- if ( path.Last() != wxFILE_SEP_PATH )
- path += wxFILE_SEP_PATH;
- wxDir d(path);
- if ( !d.IsOpened() )
- return false;
- wxString filename;
- // First delete all subdirectories: notice that we don't follow
- // symbolic links, potentially leading outside this directory, to avoid
- // unpleasant surprises.
- bool cont = d.GetFirst(&filename, wxString(),
- wxDIR_DIRS | wxDIR_HIDDEN | wxDIR_NO_FOLLOW);
- while ( cont )
- {
- wxFileName::Rmdir(path + filename, flags);
- cont = d.GetNext(&filename);
- }
- #ifndef __WINDOWS__
- if ( flags & wxPATH_RMDIR_RECURSIVE )
- {
- // Delete all files too and, for the same reasons as above, don't
- // follow symlinks which could refer to the files outside of this
- // directory and just delete the symlinks themselves.
- cont = d.GetFirst(&filename, wxString(),
- wxDIR_FILES | wxDIR_HIDDEN | wxDIR_NO_FOLLOW);
- while ( cont )
- {
- ::wxRemoveFile(path + filename);
- cont = d.GetNext(&filename);
- }
- }
- #endif // !__WINDOWS__
- }
- return ::wxRmdir(dir);
- }
- // ----------------------------------------------------------------------------
- // path normalization
- // ----------------------------------------------------------------------------
- bool wxFileName::Normalize(int flags,
- const wxString& cwd,
- wxPathFormat format)
- {
- // deal with env vars renaming first as this may seriously change the path
- if ( flags & wxPATH_NORM_ENV_VARS )
- {
- wxString pathOrig = GetFullPath(format);
- wxString path = wxExpandEnvVars(pathOrig);
- if ( path != pathOrig )
- {
- Assign(path);
- }
- }
- // the existing path components
- wxArrayString dirs = GetDirs();
- // the path to prepend in front to make the path absolute
- wxFileName curDir;
- format = GetFormat(format);
- // set up the directory to use for making the path absolute later
- if ( (flags & wxPATH_NORM_ABSOLUTE) && !IsAbsolute(format) )
- {
- if ( cwd.empty() )
- {
- curDir.AssignCwd(GetVolume());
- }
- else // cwd provided
- {
- curDir.AssignDir(cwd);
- }
- }
- // handle ~ stuff under Unix only
- if ( (format == wxPATH_UNIX) && (flags & wxPATH_NORM_TILDE) && m_relative )
- {
- if ( !dirs.IsEmpty() )
- {
- wxString dir = dirs[0u];
- if ( !dir.empty() && dir[0u] == wxT('~') )
- {
- // to make the path absolute use the home directory
- curDir.AssignDir(wxGetUserHome(dir.c_str() + 1));
- dirs.RemoveAt(0u);
- }
- }
- }
- // transform relative path into abs one
- if ( curDir.IsOk() )
- {
- // this path may be relative because it doesn't have the volume name
- // and still have m_relative=true; in this case we shouldn't modify
- // our directory components but just set the current volume
- if ( !HasVolume() && curDir.HasVolume() )
- {
- SetVolume(curDir.GetVolume());
- if ( !m_relative )
- {
- // yes, it was the case - we don't need curDir then
- curDir.Clear();
- }
- }
- // finally, prepend curDir to the dirs array
- wxArrayString dirsNew = curDir.GetDirs();
- WX_PREPEND_ARRAY(dirs, dirsNew);
- // if we used e.g. tilde expansion previously and wxGetUserHome didn't
- // return for some reason an absolute path, then curDir maybe not be absolute!
- if ( !curDir.m_relative )
- {
- // we have prepended an absolute path and thus we are now an absolute
- // file name too
- m_relative = false;
- }
- // else if (flags & wxPATH_NORM_ABSOLUTE):
- // should we warn the user that we didn't manage to make the path absolute?
- }
- // now deal with ".", ".." and the rest
- m_dirs.Empty();
- size_t count = dirs.GetCount();
- for ( size_t n = 0; n < count; n++ )
- {
- wxString dir = dirs[n];
- if ( flags & wxPATH_NORM_DOTS )
- {
- if ( dir == wxT(".") )
- {
- // just ignore
- continue;
- }
- if ( dir == wxT("..") )
- {
- if ( m_dirs.empty() )
- {
- // We have more ".." than directory components so far.
- // Don't treat this as an error as the path could have been
- // entered by user so try to handle it reasonably: if the
- // path is absolute, just ignore the extra ".." because
- // "/.." is the same as "/". Otherwise, i.e. for relative
- // paths, keep ".." unchanged because removing it would
- // modify the file a relative path refers to.
- if ( !m_relative )
- continue;
- }
- else // Normal case, go one step up.
- {
- m_dirs.pop_back();
- continue;
- }
- }
- }
- m_dirs.Add(dir);
- }
- #if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE
- if ( (flags & wxPATH_NORM_SHORTCUT) )
- {
- wxString filename;
- if (GetShortcutTarget(GetFullPath(format), filename))
- {
- m_relative = false;
- Assign(filename);
- }
- }
- #endif
- #if defined(__WIN32__)
- if ( (flags & wxPATH_NORM_LONG) && (format == wxPATH_DOS) )
- {
- Assign(GetLongPath());
- }
- #endif // Win32
- // Change case (this should be kept at the end of the function, to ensure
- // that the path doesn't change any more after we normalize its case)
- if ( (flags & wxPATH_NORM_CASE) && !IsCaseSensitive(format) )
- {
- m_volume.MakeLower();
- m_name.MakeLower();
- m_ext.MakeLower();
- // directory entries must be made lower case as well
- count = m_dirs.GetCount();
- for ( size_t i = 0; i < count; i++ )
- {
- m_dirs[i].MakeLower();
- }
- }
- return true;
- }
- #ifndef __WXWINCE__
- bool wxFileName::ReplaceEnvVariable(const wxString& envname,
- const wxString& replacementFmtString,
- wxPathFormat format)
- {
- // look into stringForm for the contents of the given environment variable
- wxString val;
- if (envname.empty() ||
- !wxGetEnv(envname, &val))
- return false;
- if (val.empty())
- return false;
- wxString stringForm = GetPath(wxPATH_GET_VOLUME, format);
- // do not touch the file name and the extension
- wxString replacement = wxString::Format(replacementFmtString, envname);
- stringForm.Replace(val, replacement);
- // Now assign ourselves the modified path:
- Assign(stringForm, GetFullName(), format);
- return true;
- }
- #endif
- bool wxFileName::ReplaceHomeDir(wxPathFormat format)
- {
- wxString homedir = wxGetHomeDir();
- if (homedir.empty())
- return false;
- wxString stringForm = GetPath(wxPATH_GET_VOLUME, format);
- // do not touch the file name and the extension
- stringForm.Replace(homedir, "~");
- // Now assign ourselves the modified path:
- Assign(stringForm, GetFullName(), format);
- return true;
- }
- // ----------------------------------------------------------------------------
- // get the shortcut target
- // ----------------------------------------------------------------------------
- // WinCE (3) doesn't have CLSID_ShellLink, IID_IShellLink definitions.
- // The .lnk file is a plain text file so it should be easy to
- // make it work. Hint from Google Groups:
- // "If you open up a lnk file, you'll see a
- // number, followed by a pound sign (#), followed by more text. The
- // number is the number of characters that follows the pound sign. The
- // characters after the pound sign are the command line (which _can_
- // include arguments) to be executed. Any path (e.g. \windows\program
- // files\myapp.exe) that includes spaces needs to be enclosed in
- // quotation marks."
- #if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE
- bool wxFileName::GetShortcutTarget(const wxString& shortcutPath,
- wxString& targetFilename,
- wxString* arguments) const
- {
- wxString path, file, ext;
- wxFileName::SplitPath(shortcutPath, & path, & file, & ext);
- HRESULT hres;
- IShellLink* psl;
- bool success = false;
- // Assume it's not a shortcut if it doesn't end with lnk
- if (ext.CmpNoCase(wxT("lnk"))!=0)
- return false;
- // create a ShellLink object
- hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
- IID_IShellLink, (LPVOID*) &psl);
- if (SUCCEEDED(hres))
- {
- IPersistFile* ppf;
- hres = psl->QueryInterface( IID_IPersistFile, (LPVOID *) &ppf);
- if (SUCCEEDED(hres))
- {
- WCHAR wsz[MAX_PATH];
- …
Large files files are truncated, but you can click here to view the full file