diff options
Diffstat (limited to 'shared')
-rw-r--r-- | shared/IFileOperation/file_op.cpp | 1 | ||||
-rw-r--r-- | shared/com_ptr.h | 23 | ||||
-rw-r--r-- | shared/custom_combo_box.cpp | 39 | ||||
-rw-r--r-- | shared/custom_combo_box.h | 7 | ||||
-rw-r--r-- | shared/custom_tooltip.cpp | 3 | ||||
-rw-r--r-- | shared/dir_name.cpp | 2 | ||||
-rw-r--r-- | shared/file_handling.cpp | 178 | ||||
-rw-r--r-- | shared/file_io.cpp | 2 | ||||
-rw-r--r-- | shared/file_traverser.cpp | 144 | ||||
-rw-r--r-- | shared/global_func.h | 2 | ||||
-rw-r--r-- | shared/localization.cpp | 29 | ||||
-rw-r--r-- | shared/localization.h | 2 | ||||
-rw-r--r-- | shared/recycler.cpp | 10 | ||||
-rw-r--r-- | shared/serialize.cpp | 2 | ||||
-rw-r--r-- | shared/serialize.h | 5 | ||||
-rw-r--r-- | shared/signal_processing.h | 166 | ||||
-rw-r--r-- | shared/symlink_target.h | 146 | ||||
-rw-r--r-- | shared/system_func.cpp | 17 | ||||
-rw-r--r-- | shared/zbase.h | 20 |
19 files changed, 427 insertions, 371 deletions
diff --git a/shared/IFileOperation/file_op.cpp b/shared/IFileOperation/file_op.cpp index 6180a561..cc8c58bc 100644 --- a/shared/IFileOperation/file_op.cpp +++ b/shared/IFileOperation/file_op.cpp @@ -53,6 +53,7 @@ bool fileop::moveToRecycleBin(const wchar_t* fileNames[], hr = fileOp->SetOperationFlags(FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_SILENT | + FOFX_EARLYFAILURE | FOF_NOERRORUI); if (FAILED(hr)) { diff --git a/shared/com_ptr.h b/shared/com_ptr.h index 1ce7eae6..52a072fa 100644 --- a/shared/com_ptr.h +++ b/shared/com_ptr.h @@ -12,7 +12,7 @@ namespace util { -/* +/* ComPtr: RAII class handling COM objects Example: @@ -39,13 +39,20 @@ public: ~ComPtr(); T** init(); //get pointer for use with ::CoCreateInstance() T* get() const; - T* release(); + T* release(); //throw() void swap(ComPtr& rhs); //throw() T* operator->() const; - operator bool() const; private: T* ptr; + + struct ConversionToBool + { + int dummy; + }; + +public: + operator int ConversionToBool::*() const; //use member pointer as implicit conversion to bool (C++ Templates - Vandevoorde/Josuttis; chapter 20) }; @@ -162,12 +169,22 @@ T* ComPtr<T>::operator->() const } +/* template <class T> inline ComPtr<T>::operator bool() const { return ptr != NULL; } +*/ + + +template <class T> +inline +ComPtr<T>::operator int ComPtr<T>::ConversionToBool::*() const +{ + return ptr != NULL ? &ConversionToBool::dummy : NULL; +} template <class S, class T> diff --git a/shared/custom_combo_box.cpp b/shared/custom_combo_box.cpp index 3c2a118c..18adb38a 100644 --- a/shared/custom_combo_box.cpp +++ b/shared/custom_combo_box.cpp @@ -18,12 +18,36 @@ CustomComboBox::CustomComboBox(wxWindow* parent, const wxValidator& validator, const wxString& name) : wxComboBox(parent, id, value, pos, size, n, choices, style, validator, name) +#if wxCHECK_VERSION(2, 9, 1) + , dropDownShown(false) +#endif { //register key event to enable item deletion this->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CustomComboBox::OnKeyEvent), NULL, this ); + +#if wxCHECK_VERSION(2, 9, 1) + this->Connect(wxEVT_COMMAND_COMBOBOX_DROPDOWN, wxCommandEventHandler(CustomComboBox::OnShowDropDown), NULL, this ); + this->Connect(wxEVT_COMMAND_COMBOBOX_CLOSEUP, wxCommandEventHandler(CustomComboBox::OnHideDropDown), NULL, this ); +#endif +} + + +#if wxCHECK_VERSION(2, 9, 1) +void CustomComboBox::OnShowDropDown(wxCommandEvent& event) +{ + dropDownShown = true; + event.Skip(); } +void CustomComboBox::OnHideDropDown(wxCommandEvent& event) +{ + dropDownShown = false; + event.Skip(); +} +#endif + + void CustomComboBox::OnKeyEvent(wxKeyEvent& event) { const int keyCode = event.GetKeyCode(); @@ -32,11 +56,16 @@ void CustomComboBox::OnKeyEvent(wxKeyEvent& event) //try to delete the currently selected config history item const int selectedItem = this->GetCurrentSelection(); if (0 <= selectedItem && selectedItem < static_cast<int>(this->GetCount()) && - (GetValue() != GetString(selectedItem) || //avoid problems when a character shall be deleted instead of list item - GetValue() == wxEmptyString)) //exception: always allow removing empty entry - { - //save old (selected) value: deletion seems to have influence on this - const wxString currentVal = this->GetValue(); +#if wxCHECK_VERSION(2, 9, 1) + dropDownShown) +#else + //what a mess...: + (GetValue() != GetString(selectedItem) || //avoid problems when a character shall be deleted instead of list item + GetValue() == wxEmptyString)) //exception: always allow removing empty entry +#endif + { + //save old (selected) value: deletion seems to have influence on this + const wxString currentVal = this->GetValue(); this->SetSelection(wxNOT_FOUND); //delete selected row diff --git a/shared/custom_combo_box.h b/shared/custom_combo_box.h index 7db8cecf..28361a30 100644 --- a/shared/custom_combo_box.h +++ b/shared/custom_combo_box.h @@ -29,6 +29,13 @@ public: private: void OnKeyEvent(wxKeyEvent& event); + +#if wxCHECK_VERSION(2, 9, 1) + void OnShowDropDown(wxCommandEvent& event); + void OnHideDropDown(wxCommandEvent& event); + + bool dropDownShown; +#endif }; diff --git a/shared/custom_tooltip.cpp b/shared/custom_tooltip.cpp index be2d11b5..5b4e5e40 100644 --- a/shared/custom_tooltip.cpp +++ b/shared/custom_tooltip.cpp @@ -34,7 +34,8 @@ CustomTooltip::PopupFrameGenerated::PopupFrameGenerated( long style ) : wxFrame(parent, id, title, pos, size, style) { this->SetSizeHints( wxDefaultSize, wxDefaultSize ); - this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK)); + this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK)); //both required: on Ubuntu background is black, foreground white! + this->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT)); // wxBoxSizer* bSizer158; bSizer158 = new wxBoxSizer( wxHORIZONTAL ); diff --git a/shared/dir_name.cpp b/shared/dir_name.cpp index 40e840f5..28c1c413 100644 --- a/shared/dir_name.cpp +++ b/shared/dir_name.cpp @@ -52,7 +52,7 @@ void setDirectoryNameImpl(const wxString& dirname, wxDirPickerCtrl* dirPicker, w const wxString dirFormatted = zToWx(getFormattedDirectoryName(wxToZ(dirname))); - tooltipWnd.SetToolTip(dirFormatted); + tooltipWnd.SetToolTip(dirFormatted); //wxComboBox bug: the edit control is not updated... hope this will be fixed: http://trac.wxwidgets.org/ticket/12659 if (staticBox) { diff --git a/shared/file_handling.cpp b/shared/file_handling.cpp index 5c6ce856..b05b9cf8 100644 --- a/shared/file_handling.cpp +++ b/shared/file_handling.cpp @@ -21,6 +21,7 @@ #include "loki/TypeManip.h" #include "loki/ScopeGuard.h" #include <map> +#include "symlink_target.h" #ifdef FFS_WIN #include "dll_loader.h" @@ -36,6 +37,10 @@ #include <utime.h> #include <cerrno> #include <sys/time.h> + +#ifdef HAVE_SELINUX +#include <selinux/selinux.h> +#endif #endif using ffs3::FileError; @@ -1129,7 +1134,7 @@ void ffs3::copyFileTimes(const Zstring& sourceObj, const Zstring& targetObj, boo namespace { #ifdef FFS_WIN -Zstring resolveDirectorySymlink(const Zstring& dirLinkName) //get full target path of symbolic link to a directory +Zstring resolveDirectorySymlink(const Zstring& dirLinkName) //get full target path of symbolic link to a directory; throw (FileError) { //open handle to target of symbolic link const HANDLE hDir = ::CreateFile(ffs3::applyLongPathPrefix(dirLinkName).c_str(), @@ -1140,7 +1145,10 @@ Zstring resolveDirectorySymlink(const Zstring& dirLinkName) //get full target pa FILE_FLAG_BACKUP_SEMANTICS, //needed to open a directory NULL); if (hDir == INVALID_HANDLE_VALUE) - return Zstring(); + { + wxString errorMessage = wxString(_("Error resolving symbolic link:")) + wxT("\n\"") + ffs3::zToWx(dirLinkName) + wxT("\""); + throw FileError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted()); + } boost::shared_ptr<void> dummy(hDir, ::CloseHandle); @@ -1159,13 +1167,17 @@ Zstring resolveDirectorySymlink(const Zstring& dirLinkName) //get full target pa if (getFinalPathNameByHandle == NULL) throw FileError(wxString(_("Error loading library function:")) + wxT("\n\"") + wxT("GetFinalPathNameByHandleW") + wxT("\"")); - const DWORD rv = (*getFinalPathNameByHandle)( + const DWORD rv = getFinalPathNameByHandle( hDir, //__in HANDLE hFile, targetPath, //__out LPTSTR lpszFilePath, BUFFER_SIZE,//__in DWORD cchFilePath, 0); //__in DWORD dwFlags if (rv >= BUFFER_SIZE || rv == 0) - return Zstring(); + { + wxString errorMessage = wxString(_("Error resolving symbolic link:")) + wxT("\n\"") + ffs3::zToWx(dirLinkName) + wxT("\""); + if (rv == 0) errorMessage += wxT("\n\n") + ffs3::getLastErrorFormatted(); + throw FileError(errorMessage); + } return targetPath; } @@ -1351,6 +1363,58 @@ void Privileges::setPrivilege(LPCTSTR privilege, bool enable) //throw FileError( } +#ifdef HAVE_SELINUX +//copy SELinux security context +void copySecurityContext(const Zstring& source, const Zstring& target, bool derefSymlinks) //throw FileError() +{ + using ffs3::zToWx; + + security_context_t contextSource = NULL; + const int rv = derefSymlinks ? + ::getfilecon (source.c_str(), &contextSource) : + ::lgetfilecon(source.c_str(), &contextSource); + if (rv < 0) + { + if ( errno == ENODATA || //no security context (allegedly) is not an error condition on SELinux + errno == EOPNOTSUPP) //extended attributes are not supported by the filesystem + return; + + wxString errorMessage = wxString(_("Error reading security context:")) + wxT("\n\"") + zToWx(source) + wxT("\""); + throw FileError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted()); + } + boost::shared_ptr<char> dummy1(contextSource, ::freecon); + + { + security_context_t contextTarget = NULL; + const int rv2 = derefSymlinks ? + ::getfilecon (target.c_str(), &contextTarget) : + ::lgetfilecon(target.c_str(), &contextTarget); + if (rv2 < 0) + { + if (errno == EOPNOTSUPP) + return; + //else: still try to set security context + } + else + { + boost::shared_ptr<char> dummy2(contextTarget, ::freecon); + if (::strcmp(contextSource, contextTarget) == 0) //nothing to do + return; + } + } + + const int rv3 = derefSymlinks ? + ::setfilecon (target.c_str(), contextSource) : + ::lsetfilecon(target.c_str(), contextSource); + if (rv3 < 0) + { + wxString errorMessage = wxString(_("Error writing security context:")) + wxT("\n\"") + zToWx(target) + wxT("\""); + throw FileError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted()); + } +} +#endif //HAVE_SELINUX + + //copy permissions for files, directories or symbolic links void ffs3::copyObjectPermissions(const Zstring& source, const Zstring& target, bool derefSymlinks) //throw FileError(); probably requires admin rights { @@ -1379,8 +1443,10 @@ void ffs3::copyObjectPermissions(const Zstring& source, const Zstring& target, b FILE_FLAG_BACKUP_SEMANTICS | (derefSymlinks ? 0 : FILE_FLAG_OPEN_REPARSE_POINT), //FILE_FLAG_BACKUP_SEMANTICS needed to open a directory NULL); if (hSource == INVALID_HANDLE_VALUE) - throw FileError(wxString(_("Error opening file:")) + wxT("\n\"") + zToWx(source) + wxT("\"") + - wxT("\n\n") + ffs3::getLastErrorFormatted()); + { + const wxString errorMessage = wxString(_("Error copying file permissions:")) + wxT("\n\"") + zToWx(source) + wxT("\" ->\n\"") + zToWx(target) + wxT("\"") + wxT("\n\n"); + throw FileError(errorMessage + ffs3::getLastErrorFormatted() + wxT(" (OR)")); + } boost::shared_ptr<void> dummy(hSource, ::CloseHandle); // DWORD rc = ::GetNamedSecurityInfo(const_cast<WCHAR*>(applyLongPathPrefix(source).c_str()), -> does NOT dereference symlinks! @@ -1396,7 +1462,7 @@ void ffs3::copyObjectPermissions(const Zstring& source, const Zstring& target, b if (rc != ERROR_SUCCESS) { const wxString errorMessage = wxString(_("Error copying file permissions:")) + wxT("\n\"") + zToWx(source) + wxT("\" ->\n\"") + zToWx(target) + wxT("\"") + wxT("\n\n"); - throw FileError(errorMessage + ffs3::getLastErrorFormatted(rc)); + throw FileError(errorMessage + ffs3::getLastErrorFormatted(rc) + wxT(" (R)")); } boost::shared_ptr<void> dummy2(buffer, ::LocalFree); @@ -1413,7 +1479,7 @@ void ffs3::copyObjectPermissions(const Zstring& source, const Zstring& target, b resetAttributes.Dismiss(); - HANDLE hTarget = ::CreateFile( targetFmt.c_str(), // lpFileName + const HANDLE hTarget = ::CreateFile( targetFmt.c_str(), // lpFileName FILE_GENERIC_WRITE | WRITE_OWNER | WRITE_DAC | ACCESS_SYSTEM_SECURITY, // dwDesiredAccess: all four seem to be required!!! FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, // dwShareMode NULL, // lpSecurityAttributes @@ -1421,8 +1487,10 @@ void ffs3::copyObjectPermissions(const Zstring& source, const Zstring& target, b FILE_FLAG_BACKUP_SEMANTICS | (derefSymlinks ? 0 : FILE_FLAG_OPEN_REPARSE_POINT), // dwFlagsAndAttributes NULL); // hTemplateFile if (hTarget == INVALID_HANDLE_VALUE) - throw FileError(wxString(_("Error opening file:")) + wxT("\n\"") + zToWx(target) + wxT("\"") + - wxT("\n\n") + ffs3::getLastErrorFormatted()); + { + const wxString errorMessage = wxString(_("Error copying file permissions:")) + wxT("\n\"") + zToWx(source) + wxT("\" ->\n\"") + zToWx(target) + wxT("\"") + wxT("\n\n"); + throw FileError(errorMessage + ffs3::getLastErrorFormatted() + wxT(" (OW)")); + } boost::shared_ptr<void> dummy3(hTarget, ::CloseHandle); // rc = ::SetNamedSecurityInfo(const_cast<WCHAR*>(applyLongPathPrefix(target).c_str()), //__in LPTSTR pObjectName, -> does NOT dereference symlinks! @@ -1438,10 +1506,15 @@ void ffs3::copyObjectPermissions(const Zstring& source, const Zstring& target, b if (rc != ERROR_SUCCESS) { const wxString errorMessage = wxString(_("Error copying file permissions:")) + wxT("\n\"") + zToWx(source) + wxT("\" ->\n\"") + zToWx(target) + wxT("\"") + wxT("\n\n"); - throw FileError(errorMessage + ffs3::getLastErrorFormatted(rc)); + throw FileError(errorMessage + ffs3::getLastErrorFormatted(rc) + wxT(" (W)")); } #elif defined FFS_LINUX + +#ifdef HAVE_SELINUX //copy SELinux security context + copySecurityContext(source, target, derefSymlinks); //throw FileError() +#endif + if (derefSymlinks) { struct stat fileInfo; @@ -1450,7 +1523,7 @@ void ffs3::copyObjectPermissions(const Zstring& source, const Zstring& target, b ::chmod(target.c_str(), fileInfo.st_mode) != 0) { const wxString errorMessage = wxString(_("Error copying file permissions:")) + wxT("\n\"") + zToWx(source) + wxT("\" ->\n\"") + zToWx(target) + wxT("\"") + wxT("\n\n"); - throw FileError(errorMessage + ffs3::getLastErrorFormatted()); + throw FileError(errorMessage + ffs3::getLastErrorFormatted() + wxT(" (R)")); } } else @@ -1461,7 +1534,7 @@ void ffs3::copyObjectPermissions(const Zstring& source, const Zstring& target, b (!symlinkExists(target) && ::chmod(target.c_str(), fileInfo.st_mode) != 0)) //setting access permissions doesn't make sense for symlinks on Linux: there is no lchmod() { const wxString errorMessage = wxString(_("Error copying file permissions:")) + wxT("\n\"") + zToWx(source) + wxT("\" ->\n\"") + zToWx(target) + wxT("\"") + wxT("\n\n"); - throw FileError(errorMessage + ffs3::getLastErrorFormatted()); + throw FileError(errorMessage + ffs3::getLastErrorFormatted() + wxT(" (W)")); } } #endif @@ -1518,39 +1591,74 @@ void createDirectoryRecursively(const Zstring& directory, const Zstring& templat const bool isSymlink = (templateAttr & FILE_ATTRIBUTE_REPARSE_POINT) != 0; //syntax required to shut MSVC up //symbolic link handling - if (!copyDirectorySymLinks && isSymlink) //create directory based on target of symbolic link + if (isSymlink) { - //get target directory of symbolic link - const Zstring linkPath = resolveDirectorySymlink(templateDir); - if (linkPath.empty()) + if (!copyDirectorySymLinks) //create directory based on target of symbolic link { - if (level != 0) return; - throw FileError(wxString(_("Error resolving symbolic link:")) + wxT("\n\"") + templateDir.c_str() + wxT("\"")); - } + //get target directory of symbolic link + Zstring linkPath; + try + { + linkPath = resolveDirectorySymlink(templateDir); //throw (FileError) + } + catch (FileError&) + { + //dereferencing a symbolic link usually fails if it is located on network drive or client is XP: NOT really an error... + if (!::CreateDirectory(applyLongPathPrefixCreateDir(directory).c_str(), // pointer to a directory path string + NULL)) + { + if (level != 0) return; + const wxString errorMessage = wxString(_("Error creating directory:")) + wxT("\n\"") + directory.c_str() + wxT("\""); + throw FileError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted()); + } + return; + } - if (!::CreateDirectoryEx( // this function automatically copies symbolic links if encountered - applyLongPathPrefix(linkPath).c_str(), // pointer to path string of template directory - applyLongPathPrefixCreateDir(directory).c_str(), // pointer to a directory path string - NULL)) + if (!::CreateDirectoryEx( // this function automatically copies symbolic links if encountered + applyLongPathPrefix(linkPath).c_str(), // pointer to path string of template directory + applyLongPathPrefixCreateDir(directory).c_str(), // pointer to a directory path string + NULL)) + { + if (level != 0) return; + const wxString errorMessage = wxString(_("Error creating directory:")) + wxT("\n\"") + directory.c_str() + wxT("\""); + throw FileError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted()); + } + } + else //copy symbolic link { - if (level != 0) return; - const wxString errorMessage = wxString(_("Error creating directory:")) + wxT("\n\"") + directory.c_str() + wxT("\""); - throw FileError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted()); + const Zstring linkPath = getSymlinkRawTargetString(templateDir); //accept broken symlinks; throw (FileError) + + //dynamically load windows API function + typedef BOOLEAN (WINAPI *CreateSymbolicLinkFunc)( + LPCTSTR lpSymlinkFileName, + LPCTSTR lpTargetFileName, + DWORD dwFlags); + static const CreateSymbolicLinkFunc createSymbolicLink = util::getDllFun<CreateSymbolicLinkFunc>(L"kernel32.dll", "CreateSymbolicLinkW"); + if (createSymbolicLink == NULL) + throw FileError(wxString(_("Error loading library function:")) + wxT("\n\"") + wxT("CreateSymbolicLinkW") + wxT("\"")); + + if (!createSymbolicLink( //seems no long path prefix is required... + directory.c_str(), //__in LPTSTR lpSymlinkFileName, + linkPath.c_str(), //__in LPTSTR lpTargetFileName, + SYMBOLIC_LINK_FLAG_DIRECTORY)) //__in DWORD dwFlags + { + //if (level != 0) return; + const wxString errorMessage = wxString(_("Error copying symbolic link:")) + wxT("\n\"") + templateDir.c_str() + wxT("\" ->\n\"") + directory.c_str() + wxT("\""); + throw FileError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted()); + } } } - else //in all other cases + else //no symbolic link { - if (!::CreateDirectoryEx( // this function automatically copies symbolic links if encountered + //automatically copies symbolic links if encountered: unfortunately it doesn't copy symlinks over network shares but silently creates empty folders instead (on XP)! + //also it isn't able to copy most junctions because of missing permissions (although target path can be retrieved!) + if (!::CreateDirectoryEx( applyLongPathPrefix(templateDir).c_str(), // pointer to path string of template directory applyLongPathPrefixCreateDir(directory).c_str(), // pointer to a directory path string NULL)) { if (level != 0) return; - const wxString errorMessage = isSymlink ? - //give a more meaningful errormessage if copying a symbolic link failed, e.g. "C:\Users\ZenJu\Application Data" - (wxString(_("Error copying symbolic link:")) + wxT("\n\"") + templateDir.c_str() + wxT("\" ->\n\"") + directory.c_str() + wxT("\"")) : - - (wxString(_("Error creating directory:")) + wxT("\n\"") + directory.c_str() + wxT("\"")); + const wxString errorMessage = wxString(_("Error creating directory:")) + wxT("\n\"") + directory.c_str() + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted()); } } @@ -1868,7 +1976,6 @@ void ffs3::copyFile(const Zstring& sourceFile, //invoke callback method to update progress indicators if (callback != NULL) - { switch (callback->updateCopyStatus(totalBytesTransferred)) { case CopyFileCallback::CONTINUE: @@ -1878,7 +1985,6 @@ void ffs3::copyFile(const Zstring& sourceFile, throw FileError(wxString(_("Error copying file:")) + wxT("\n\"") + zToWx(sourceFile) + wxT("\" ->\n\"") + zToWx(targetFile) + wxT("\"\n\n") + _("Operation aborted!")); } - } } while (!fileIn.eof()); diff --git a/shared/file_io.cpp b/shared/file_io.cpp index 95c14c49..78796bbe 100644 --- a/shared/file_io.cpp +++ b/shared/file_io.cpp @@ -12,7 +12,7 @@ #ifdef FFS_WIN #include "long_path_prefix.h" #elif defined FFS_LINUX -#include <errno.h> +#include <cerrno> #endif using namespace ffs3; diff --git a/shared/file_traverser.cpp b/shared/file_traverser.cpp index 5d3f75f4..f2b531e9 100644 --- a/shared/file_traverser.cpp +++ b/shared/file_traverser.cpp @@ -5,18 +5,16 @@ // ************************************************************************** // #include "file_traverser.h" +#include <limits> #include "system_constants.h" #include "system_func.h" #include <wx/intl.h> #include "string_conv.h" -#include <boost/shared_ptr.hpp> -#include <boost/scoped_array.hpp> #include "assert_static.h" -#include <limits> +#include "symlink_target.h" #ifdef FFS_WIN #include <wx/msw/wrapwin.h> //includes "windows.h" -#include "WinIoCtl.h" #include "long_path_prefix.h" #include "dst_hack.h" @@ -27,130 +25,6 @@ #endif -//Note: this class is superfluous for 64 bit applications! -//class DisableWow64Redirection -//{ -//public: -// DisableWow64Redirection() : -// wow64DisableWow64FsRedirection(util::getDllFun<Wow64DisableWow64FsRedirectionFunc>(L"kernel32.dll", "Wow64DisableWow64FsRedirection")), -// wow64RevertWow64FsRedirection(util::getDllFun<Wow64RevertWow64FsRedirectionFunc>(L"kernel32.dll", "Wow64RevertWow64FsRedirection")), -// oldValue(NULL) -// { -// if ( wow64DisableWow64FsRedirection && -// wow64RevertWow64FsRedirection) -// (*wow64DisableWow64FsRedirection)(&oldValue); //__out PVOID *OldValue -// } -// -// ~DisableWow64Redirection() -// { -// if ( wow64DisableWow64FsRedirection && -// wow64RevertWow64FsRedirection) -// (*wow64RevertWow64FsRedirection)(oldValue); //__in PVOID OldValue -// } -// -//private: -// typedef BOOL (WINAPI *Wow64DisableWow64FsRedirectionFunc)(PVOID* OldValue); -// typedef BOOL (WINAPI *Wow64RevertWow64FsRedirectionFunc)(PVOID OldValue); -// -// const Wow64DisableWow64FsRedirectionFunc wow64DisableWow64FsRedirection; -// const Wow64RevertWow64FsRedirectionFunc wow64RevertWow64FsRedirection; -// -// PVOID oldValue; -//}; - -#ifdef _MSC_VER //I don't have Windows Driver Kit at hands right now, so unfortunately we need to redefine this structures and cross fingers... -typedef struct _REPARSE_DATA_BUFFER -{ - ULONG ReparseTag; - USHORT ReparseDataLength; - USHORT Reserved; - union - { - struct - { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - ULONG Flags; - WCHAR PathBuffer[1]; - } SymbolicLinkReparseBuffer; - struct - { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - WCHAR PathBuffer[1]; - } MountPointReparseBuffer; - struct - { - UCHAR DataBuffer[1]; - } GenericReparseBuffer; - }; -} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; -#define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer) -#endif - - -Zstring getSymlinkTarget(const Zstring& linkPath) //throw(); returns empty string on error -{ -#ifdef FFS_WIN -//FSCTL_GET_REPARSE_POINT: http://msdn.microsoft.com/en-us/library/aa364571(VS.85).aspx - - const HANDLE hLink = ::CreateFile(linkPath.c_str(), - GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, - NULL); - if (hLink == INVALID_HANDLE_VALUE) - return Zstring(); - - boost::shared_ptr<void> dummy(hLink, ::CloseHandle); - - //respect alignment issues... - const size_t bufferSize = REPARSE_DATA_BUFFER_HEADER_SIZE + MAXIMUM_REPARSE_DATA_BUFFER_SIZE; - boost::scoped_array<char> buffer(new char[bufferSize]); - - DWORD bytesReturned; //dummy value required by FSCTL_GET_REPARSE_POINT! - if (!::DeviceIoControl(hLink, //__in HANDLE hDevice, - FSCTL_GET_REPARSE_POINT, //__in DWORD dwIoControlCode, - NULL, //__in_opt LPVOID lpInBuffer, - 0, //__in DWORD nInBufferSize, - buffer.get(), //__out_opt LPVOID lpOutBuffer, - bufferSize, //__in DWORD nOutBufferSize, - &bytesReturned, //__out_opt LPDWORD lpBytesReturned, - NULL)) //__inout_opt LPOVERLAPPED lpOverlapped - return Zstring(); - - REPARSE_DATA_BUFFER& reparseData = *reinterpret_cast<REPARSE_DATA_BUFFER*>(buffer.get()); //REPARSE_DATA_BUFFER needs to be artificially enlarged! - - if (reparseData.ReparseTag == IO_REPARSE_TAG_SYMLINK) - return Zstring(reparseData.SymbolicLinkReparseBuffer.PathBuffer + reparseData.SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR), - reparseData.SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR)); - else if (reparseData.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) - return Zstring(reparseData.MountPointReparseBuffer.PathBuffer + reparseData.MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR), - reparseData.MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR)); - else - return Zstring(); //unknown reparse point - -#elif defined FFS_LINUX - const int BUFFER_SIZE = 10000; - char buffer[BUFFER_SIZE]; - - const int bytesWritten = ::readlink(linkPath.c_str(), buffer, BUFFER_SIZE); - if (bytesWritten < 0 || bytesWritten >= BUFFER_SIZE) - return Zstring(); //error - - buffer[bytesWritten] = 0; //set null-terminating char - - return buffer; -#endif -} - - #ifdef FFS_WIN inline wxLongLong getWin32TimeInformation(const FILETIME& lastWriteTime) @@ -292,8 +166,13 @@ private: if (isSymbolicLink && !followSymlinks) //evaluate symlink directly { TraverseCallback::SymlinkInfo details; + try + { + details.targetPath = getSymlinkRawTargetString(fullName); //throw (FileError) + } + catch (FileError&) {} + details.lastWriteTimeRaw = getWin32TimeInformation(fileMetaData.ftLastWriteTime); - details.targetPath = getSymlinkTarget(fullName); //throw(); returns empty string on error details.dirLink = (fileMetaData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; //directory symlinks have this flag on Windows sink.onSymlink(shortName, fullName, details); } @@ -418,8 +297,13 @@ private: else //evaluate symlink directly { TraverseCallback::SymlinkInfo details; + try + { + details.targetPath = getSymlinkRawTargetString(fullName); //throw (FileError) + } + catch (FileError&) {} + details.lastWriteTimeRaw = fileInfo.st_mtime; //UTC time(ANSI C format); unit: 1 second - details.targetPath = getSymlinkTarget(fullName); //throw(); returns empty string on error details.dirLink = ::stat(fullName.c_str(), &fileInfo) == 0 && S_ISDIR(fileInfo.st_mode); //S_ISDIR and S_ISLNK are mutually exclusive on Linux => need to follow link sink.onSymlink(shortName, fullName, details); continue; diff --git a/shared/global_func.h b/shared/global_func.h index c3994ca0..20221f63 100644 --- a/shared/global_func.h +++ b/shared/global_func.h @@ -192,7 +192,7 @@ template <class ForwardIterator, class T, typename Compare> inline ForwardIterator common::custom_binary_search(ForwardIterator first, ForwardIterator last, const T& value, Compare comp) { - first = lower_bound(first, last, value, comp); + first = std::lower_bound(first, last, value, comp); if (first != last && !comp(value, *first)) return first; else diff --git a/shared/localization.cpp b/shared/localization.cpp index ef3e02d2..ae9b5143 100644 --- a/shared/localization.cpp +++ b/shared/localization.cpp @@ -48,7 +48,7 @@ const std::vector<ffs3::LocInfoLine>& LocalizationInfo::getMapping() namespace { -struct CompareByName + struct CompareByName : public std::binary_function<ffs3::LocInfoLine, ffs3::LocInfoLine, bool> { bool operator()(const ffs3::LocInfoLine& lhs, const ffs3::LocInfoLine& rhs) const { @@ -121,7 +121,7 @@ LocalizationInfo::LocalizationInfo() newEntry.languageID = wxLANGUAGE_DUTCH; newEntry.languageName = wxT("Nederlands"); newEntry.languageFile = wxT("dutch.lng"); - newEntry.translatorName = wxT("Mikhail Frolov"); + newEntry.translatorName = wxT("Dion van Lieshout"); newEntry.languageFlag = wxT("holland.png"); locMapping.push_back(newEntry); @@ -184,7 +184,7 @@ LocalizationInfo::LocalizationInfo() newEntry.languageID = wxLANGUAGE_TURKISH; newEntry.languageName = wxT("Türkçe"); newEntry.languageFile = wxT("turkish.lng"); - newEntry.translatorName = wxT("H.Barbaros BIÇAKCI"); + newEntry.translatorName = wxT("Kaya Zeren"); newEntry.languageFlag = wxT("turkey.png"); locMapping.push_back(newEntry); @@ -481,7 +481,7 @@ private: }; -void CustomLocale::setLanguage(const int language) +void CustomLocale::setLanguage(int language) { currentLanguage = language; @@ -544,3 +544,24 @@ const wxChar* CustomLocale::GetString(const wxChar* szOrigString, const wxChar* //fallback return szOrigString; } + + + +/* + +wxWidgets 2.9.1: + +class CustomTranslation : public wxTranslations +{ + virtual const wxString& GetString(const wxString& origString, + const wxString& domain = wxEmptyString) const + { + static const wxString blah = "map origString to translation by some arbitrary means"; + return blah; + } + + wxTranslations::Set(new CustomTranslation); + +}; + +*/ diff --git a/shared/localization.h b/shared/localization.h index 1c1773e9..9435030d 100644 --- a/shared/localization.h +++ b/shared/localization.h @@ -49,7 +49,7 @@ class CustomLocale : public wxLocale public: static CustomLocale& getInstance(); - void setLanguage(const int language); + void setLanguage(int language); int getLanguage() const { diff --git a/shared/recycler.cpp b/shared/recycler.cpp index 31257a65..2ee23462 100644 --- a/shared/recycler.cpp +++ b/shared/recycler.cpp @@ -88,11 +88,13 @@ void moveToWindowsRecycler(const std::vector<Zstring>& filesToDelete) //throw ( using namespace fileop; - static const MoveToRecycleBinFct moveToRecycler = - util::getDllFun<MoveToRecycleBinFct>(getRecyclerDllName().c_str(), moveToRecycleBinFctName); + static MoveToRecycleBinFct moveToRecycler = NULL; + if (!moveToRecycler) + moveToRecycler = util::getDllFun<MoveToRecycleBinFct>(getRecyclerDllName().c_str(), moveToRecycleBinFctName); - static const GetLastErrorFct getLastError = - util::getDllFun<GetLastErrorFct>(getRecyclerDllName().c_str(), getLastErrorFctName); + static GetLastErrorFct getLastError = NULL; + if (!getLastError) + getLastError = util::getDllFun<GetLastErrorFct>(getRecyclerDllName().c_str(), getLastErrorFctName); if (moveToRecycler == NULL || getLastError == NULL) throw FileError(wxString(_("Error moving to Recycle Bin:")) + wxT("\n\"") + fileNames[0] + wxT("\"\n\n") + //report first file only... better than nothing diff --git a/shared/serialize.cpp b/shared/serialize.cpp index cf6d96b1..f5765d3d 100644 --- a/shared/serialize.cpp +++ b/shared/serialize.cpp @@ -51,5 +51,3 @@ void WriteOutputStream::writeArrayC(const std::vector<char>& buffer) const throwWriteError(); } } - - diff --git a/shared/serialize.h b/shared/serialize.h index 7c4fcd5e..5f1d5fbf 100644 --- a/shared/serialize.h +++ b/shared/serialize.h @@ -12,6 +12,7 @@ #include "file_error.h" #include <boost/scoped_array.hpp> #include <boost/shared_ptr.hpp> +#include <boost/cstdint.hpp> namespace util { @@ -126,7 +127,7 @@ void writeNumber(wxOutputStream& stream, T number) inline -Zstring readString(wxInputStream& stream) //read string from file stream +Zstring readString(wxInputStream& stream) { const size_t strLength = readNumber<size_t>(stream); if (strLength <= 1000) @@ -145,7 +146,7 @@ Zstring readString(wxInputStream& stream) //read string from file stream inline -void writeString(wxOutputStream& stream, const Zstring& str) //write string to filestream +void writeString(wxOutputStream& stream, const Zstring& str) { writeNumber<size_t>(stream, str.length()); stream.Write(str.c_str(), sizeof(Zchar) * str.length()); diff --git a/shared/signal_processing.h b/shared/signal_processing.h deleted file mode 100644 index 857d0b12..00000000 --- a/shared/signal_processing.h +++ /dev/null @@ -1,166 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2010 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** -// -#include <algorithm> -#include <limits> -#include <numeric> - - -namespace util -{ -template <class T> -T abs(T value); - -int round(double d); //little rounding function - -template <class T> -bool isNull(T number); - -//---------------------------------------------------------------------------------- -// smoothen data ranges through a window around each data point | -//---------------------------------------------------------------------------------- -template <class InputIterator, class OutputIterator> -void smoothen(InputIterator first, InputIterator last, OutputIterator result, size_t windowSize); //default implementation: averaging - -template <class InputIterator, class OutputIterator, class DataProcessor> -void smoothen(InputIterator first, InputIterator last, OutputIterator result, size_t windowSize, DataProcessor proc); -/* -DataProcessor is an abstraction for data evaluation. A valid implementation needs to support three properties: -- add data entry at window front: operator+=(ValueType value) -- remove data entry at window back: operator-=(ValueType value) -- evaluate smoothed middle value: ValueType operator()(size_t windowSize) -*/ -//---------------------------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - -//################# inline implementation ######################### -template <class T> -inline -T abs(T value) -{ - return value < 0 ? -value : value; -} - - -template <class T> -inline -bool isNull(T value) -{ - return abs(number) <= std::numeric_limits<T>::epsilon(); //epsilon == 0 for integer types, therefore less-equal(!) -} - - -inline -int round(double d) -{ - return static_cast<int>(d < 0 ? d - .5 : d + .5); -} - - -template <class InputIterator, class OutputIterator, class DataProcessor> -inline -void smoothen(InputIterator first, InputIterator last, OutputIterator result, size_t windowSize, DataProcessor proc) -{ - windowSize = std::min(windowSize, static_cast<size_t>(last - first)); //std::distance() not used to enforce random access iterator requirement - - if (windowSize <= 1) - { - std::copy(first, last, result); - return; - } - - const size_t firstHalf = windowSize / 2; - const size_t secondHalf = windowSize - firstHalf; - - //preparation - for (InputIterator i = first; i != first + secondHalf; ++i) - proc += *i; - - //beginning - for (InputIterator i = first; i != first + firstHalf; ++i) - { - *result++ = proc(i - first + secondHalf); - proc += *(i + secondHalf); - } - - //main - for (InputIterator i = first + firstHalf; i != last - secondHalf; ++i) - { - *result++ = proc(windowSize); - proc += *(i + secondHalf); - proc -= *(i - firstHalf); - } - - //ending - for (InputIterator i = last - secondHalf; i != last; ++i) - { - *result++ = proc(windowSize - (i - last + secondHalf)); - proc -= *(i - firstHalf); - } -} - - -template <class ValueType> -class ProcessorAverage -{ -public: - ProcessorAverage() : valueAcc() {} - - //add front data entry - ProcessorAverage& operator+=(ValueType value) - { - valueAcc += value; - return *this; - } - - //remove rear data entry - ProcessorAverage& operator-=(ValueType value) - { - valueAcc -= value; - return *this; - } - - //evaluate smoothed value - ValueType operator()(size_t windowSize) const - { - return valueAcc / windowSize; - } - -private: - ValueType valueAcc; //accumulated values -}; - - - -template <class InputIterator, class OutputIterator> -inline -void smoothen(InputIterator first, InputIterator last, OutputIterator result, size_t windowSize) -{ - typedef typename std::iterator_traits<InputIterator>::value_type ValueType; - smoothen(first, last, result, windowSize, ProcessorAverage<ValueType>()); -} - -}
\ No newline at end of file diff --git a/shared/symlink_target.h b/shared/symlink_target.h new file mode 100644 index 00000000..c68d5229 --- /dev/null +++ b/shared/symlink_target.h @@ -0,0 +1,146 @@ +// ************************************************************************** +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * +// * Copyright (C) 2008-2010 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** +// +#ifndef SYMLINK_WIN_H_INCLUDED +#define SYMLINK_WIN_H_INCLUDED + +#include <boost/shared_ptr.hpp> +#include <boost/scoped_array.hpp> +#include "system_func.h" +#include <wx/intl.h> +#include "string_conv.h" +#include "file_error.h" + +#ifdef FFS_WIN +#include <wx/msw/wrapwin.h> //includes "windows.h" +#include "WinIoCtl.h" +#include "long_path_prefix.h" + +#elif defined FFS_LINUX +#include <unistd.h> +#endif + + +#ifdef _MSC_VER //I don't have Windows Driver Kit at hands right now, so unfortunately we need to redefine this structures and cross fingers... +typedef struct _REPARSE_DATA_BUFFER +{ + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union + { + struct + { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct + { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct + { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + }; +} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; +#define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer) +#endif + +namespace +{ + //retrieve raw target data of symlink or junction +Zstring getSymlinkRawTargetString(const Zstring& linkPath) //throw (FileError) +{ + using ffs3::zToWx; + using ffs3::FileError; +#ifdef FFS_WIN +//FSCTL_GET_REPARSE_POINT: http://msdn.microsoft.com/en-us/library/aa364571(VS.85).aspx + + const HANDLE hLink = ::CreateFile(ffs3::applyLongPathPrefix(linkPath).c_str(), + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, + NULL); + if (hLink == INVALID_HANDLE_VALUE) + { + wxString errorMessage = wxString(_("Error resolving symbolic link:")) + wxT("\n\"") + ffs3::zToWx(linkPath) + wxT("\""); + throw FileError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted()); + } + boost::shared_ptr<void> dummy(hLink, ::CloseHandle); + + //respect alignment issues... + const size_t bufferSize = REPARSE_DATA_BUFFER_HEADER_SIZE + MAXIMUM_REPARSE_DATA_BUFFER_SIZE; + boost::scoped_array<char> buffer(new char[bufferSize]); + + DWORD bytesReturned; //dummy value required by FSCTL_GET_REPARSE_POINT! + if (!::DeviceIoControl(hLink, //__in HANDLE hDevice, + FSCTL_GET_REPARSE_POINT, //__in DWORD dwIoControlCode, + NULL, //__in_opt LPVOID lpInBuffer, + 0, //__in DWORD nInBufferSize, + buffer.get(), //__out_opt LPVOID lpOutBuffer, + bufferSize, //__in DWORD nOutBufferSize, + &bytesReturned, //__out_opt LPDWORD lpBytesReturned, + NULL)) //__inout_opt LPOVERLAPPED lpOverlapped + { + wxString errorMessage = wxString(_("Error resolving symbolic link:")) + wxT("\n\"") + ffs3::zToWx(linkPath) + wxT("\""); + throw FileError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted()); + } + + REPARSE_DATA_BUFFER& reparseData = *reinterpret_cast<REPARSE_DATA_BUFFER*>(buffer.get()); //REPARSE_DATA_BUFFER needs to be artificially enlarged! + + Zstring output; + if (reparseData.ReparseTag == IO_REPARSE_TAG_SYMLINK) + { + output = Zstring(reparseData.SymbolicLinkReparseBuffer.PathBuffer + reparseData.SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR), + reparseData.SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR)); + } + else if (reparseData.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) + { + output = Zstring(reparseData.MountPointReparseBuffer.PathBuffer + reparseData.MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR), + reparseData.MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR)); + } + else + { + wxString errorMessage = wxString(_("Error resolving symbolic link:")) + wxT("\n\"") + ffs3::zToWx(linkPath) + wxT("\""); + throw FileError(errorMessage + wxT("\n\n") + wxT("Not a symbolic link or junction!")); + } + + //absolute symlinks and junctions technically start with \??\ while relative ones do not + if (output.StartsWith(Zstr("\\??\\"))) + output = Zstring(output.c_str() + 4, output.length() - 4); + + return output; + +#elif defined FFS_LINUX + const int BUFFER_SIZE = 10000; + char buffer[BUFFER_SIZE]; + + const int bytesWritten = ::readlink(linkPath.c_str(), buffer, BUFFER_SIZE); + if (bytesWritten < 0 || bytesWritten >= BUFFER_SIZE) + { + wxString errorMessage = wxString(_("Error resolving symbolic link:")) + wxT("\n\"") + zToWx(linkPath) + wxT("\""); + if (bytesWritten < 0) errorMessage += wxString(wxT("\n\n")) + ffs3::getLastErrorFormatted(); + throw FileError(errorMessage); + } + buffer[bytesWritten] = 0; //set null-terminating char + + return buffer; +#endif +} +} + +#endif // SYMLINK_WIN_H_INCLUDED diff --git a/shared/system_func.cpp b/shared/system_func.cpp index 71335d71..4f60f724 100644 --- a/shared/system_func.cpp +++ b/shared/system_func.cpp @@ -25,11 +25,20 @@ wxString ffs3::getLastErrorFormatted(unsigned long lastError) //try to get addit wxString output = wxString(wxT("Windows Error Code ")) + wxString::Format(wxT("%u"), lastError); - WCHAR buffer[1001]; - if (::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_MAX_WIDTH_MASK, 0, lastError, 0, buffer, 1001, NULL) != 0) - output += wxString(wxT(": ")) + buffer; + LPWSTR buffer = NULL; + if (::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_MAX_WIDTH_MASK | + FORMAT_MESSAGE_IGNORE_INSERTS | //important: without this flag ::FormatMessage() will fail if message contains placeholders + FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, lastError, 0, reinterpret_cast<LPWSTR>(&buffer), 0, NULL) != 0) + { + if (buffer) //just to be sure + { + output += wxString(wxT(": ")) + buffer; + ::LocalFree(buffer); + } + } + ::SetLastError(lastError); //restore last error - ::SetLastError(lastError); //restore last error return output; } diff --git a/shared/zbase.h b/shared/zbase.h index efaa103c..1caf0e44 100644 --- a/shared/zbase.h +++ b/shared/zbase.h @@ -289,22 +289,22 @@ private: }; template <class T, template <class, class> class SP, class AP> bool operator==(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs); -template <class T, template <class, class> class SP, class AP> bool operator==(const Zbase<T, SP, AP>& lhs, const T* rhs); -template <class T, template <class, class> class SP, class AP> bool operator==(const T* lhs, const Zbase<T, SP, AP>& rhs); +template <class T, template <class, class> class SP, class AP> bool operator==(const Zbase<T, SP, AP>& lhs, const T* rhs); +template <class T, template <class, class> class SP, class AP> bool operator==(const T* lhs, const Zbase<T, SP, AP>& rhs); template <class T, template <class, class> class SP, class AP> bool operator!=(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs); -template <class T, template <class, class> class SP, class AP> bool operator!=(const Zbase<T, SP, AP>& lhs, const T* rhs); -template <class T, template <class, class> class SP, class AP> bool operator!=(const T* lhs, const Zbase<T, SP, AP>& rhs); +template <class T, template <class, class> class SP, class AP> bool operator!=(const Zbase<T, SP, AP>& lhs, const T* rhs); +template <class T, template <class, class> class SP, class AP> bool operator!=(const T* lhs, const Zbase<T, SP, AP>& rhs); template <class T, template <class, class> class SP, class AP> bool operator< (const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs); -template <class T, template <class, class> class SP, class AP> bool operator< (const Zbase<T, SP, AP>& lhs, const T* rhs); -template <class T, template <class, class> class SP, class AP> bool operator< (const T* lhs, const Zbase<T, SP, AP>& rhs); +template <class T, template <class, class> class SP, class AP> bool operator< (const Zbase<T, SP, AP>& lhs, const T* rhs); +template <class T, template <class, class> class SP, class AP> bool operator< (const T* lhs, const Zbase<T, SP, AP>& rhs); template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs); -template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+(const Zbase<T, SP, AP>& lhs, const T* rhs); -template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+(const T* lhs, const Zbase<T, SP, AP>& rhs); -template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+( T lhs, const Zbase<T, SP, AP>& rhs); -template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+(const Zbase<T, SP, AP>& lhs, T rhs); +template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+(const Zbase<T, SP, AP>& lhs, const T* rhs); +template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+(const T* lhs, const Zbase<T, SP, AP>& rhs); +template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+( T lhs, const Zbase<T, SP, AP>& rhs); +template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+(const Zbase<T, SP, AP>& lhs, T rhs); |