| OLD | NEW |
| 1 #include <functional> | 1 #include <functional> |
| 2 #include <memory> | 2 #include <memory> |
| 3 #include <sstream> | 3 #include <sstream> |
| 4 | 4 |
| 5 #include <Windows.h> | 5 #include <Windows.h> |
| 6 #include <Msi.h> | |
| 7 | 6 |
| 8 #include <AdblockPlus/FileSystem.h> | 7 #include <AdblockPlus/FileSystem.h> |
| 9 #include <AdblockPlus/WebRequest.h> | 8 #include <AdblockPlus/WebRequest.h> |
| 10 | 9 |
| 10 #include "../shared/AutoHandle.h" |
| 11 #include "../shared/Dictionary.h" | 11 #include "../shared/Dictionary.h" |
| 12 #include "../shared/Utils.h" | 12 #include "../shared/Utils.h" |
| 13 #include "Debug.h" | 13 #include "Debug.h" |
| 14 #include "Resource.h" | 14 #include "Resource.h" |
| 15 #include "Updater.h" | 15 #include "Updater.h" |
| 16 | 16 |
| 17 namespace | 17 namespace |
| 18 { | 18 { |
| 19 typedef std::function<void()> ThreadCallbackType; | 19 typedef std::function<void()> ThreadCallbackType; |
| 20 typedef std::function<void(HWND)> DialogCallbackType; | 20 typedef std::function<void(HWND)> DialogCallbackType; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 78 } | 78 } |
| 79 return FALSE; | 79 return FALSE; |
| 80 } | 80 } |
| 81 | 81 |
| 82 DWORD RunThread(LPVOID param) | 82 DWORD RunThread(LPVOID param) |
| 83 { | 83 { |
| 84 std::auto_ptr<ThreadCallbackType> callback(reinterpret_cast<ThreadCallbackTy
pe*>(param)); | 84 std::auto_ptr<ThreadCallbackType> callback(reinterpret_cast<ThreadCallbackTy
pe*>(param)); |
| 85 (*callback)(); | 85 (*callback)(); |
| 86 return 0; | 86 return 0; |
| 87 } | 87 } |
| 88 |
| 89 std::wstring EscapeCommandLineArg(const std::wstring& arg) |
| 90 { |
| 91 // This does the inverse of CommandLineToArgvW(). See |
| 92 // http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx for |
| 93 // a description of the rules - the backslash rules are very non-obvious. |
| 94 std::wstring result = arg; |
| 95 size_t pos = arg.find(L'"'); |
| 96 while (pos != std::wstring::npos) |
| 97 { |
| 98 // Protect the quotation mark |
| 99 result.insert(pos, 1, L'\\'); |
| 100 pos++; |
| 101 |
| 102 // Protect any of the preceding backslashes |
| 103 for (int offset = -2; pos + offset >= 0 && result[pos + offset] == L'\\';
offset -= 2) |
| 104 { |
| 105 result.insert(pos + offset, 1, L'\\'); |
| 106 pos++; |
| 107 } |
| 108 |
| 109 // Find next quotation mark |
| 110 pos = arg.find(L'"', pos); |
| 111 } |
| 112 return L'"' + result + L'"'; |
| 113 } |
| 114 |
| 115 BOOL InstallUpdate(const std::wstring& path) |
| 116 { |
| 117 WCHAR sysDir[MAX_PATH]; |
| 118 UINT sysDirLen = GetSystemDirectoryW(sysDir, sizeof(sysDir) / sizeof(sysDir[
0])); |
| 119 if (sysDirLen == 0) |
| 120 return false; |
| 121 |
| 122 std::wstring msiexec = std::wstring(sysDir, sysDirLen) + L"\\msiexec.exe"; |
| 123 |
| 124 std::wstring params = L"/i " + EscapeCommandLineArg(path) |
| 125 + L" ACTION=INSTALL INSTALLUILEVEL=2 REINSTALL=ALL" |
| 126 L" REINSTALLMODE=vomus MSIENFORCEUPGRADECOMPONENTRULES=1"; |
| 127 |
| 128 HINSTANCE instance = ShellExecuteW(NULL, L"runas", msiexec.c_str(), params.c
_str(), NULL, SW_HIDE); |
| 129 if (reinterpret_cast<int>(instance) <= 32) |
| 130 return false; |
| 131 |
| 132 // As far as we are concerned everything is fine - MSI service will handle |
| 133 // further errors. |
| 134 return true; |
| 135 } |
| 88 } | 136 } |
| 89 | 137 |
| 90 Updater::Updater(AdblockPlus::JsEnginePtr jsEngine, const std::string& url) | 138 Updater::Updater(AdblockPlus::JsEnginePtr jsEngine, const std::string& url) |
| 91 : jsEngine(jsEngine), url(url), tempFile(GetAppDataPath() + L"\\update.msi") | 139 : jsEngine(jsEngine), url(url), tempFile(GetAppDataPath() + L"\\update.msi") |
| 92 { | 140 { |
| 93 } | 141 } |
| 94 | 142 |
| 95 void Updater::Update() | 143 void Updater::Update() |
| 96 { | 144 { |
| 97 Debug("Update available: " + url); | 145 Debug("Update available: " + url); |
| 98 | 146 |
| 99 if (DialogBox(NULL, MAKEINTRESOURCE(IDD_UPDATEDIALOG), GetDesktopWindow(), | 147 if (DialogBox(NULL, MAKEINTRESOURCE(IDD_UPDATEDIALOG), GetDesktopWindow(), |
| 100 reinterpret_cast<DLGPROC>(&UpdateDlgProc)) == IDOK) | 148 reinterpret_cast<DLGPROC>(&UpdateDlgProc)) == IDOK) |
| 101 { | 149 { |
| 102 Debug("User accepted update"); | 150 Debug("User accepted update"); |
| 103 | 151 |
| 152 DialogCallbackType* callback = new DialogCallbackType(std::bind(&Updater::St
artDownload, |
| 153 this, std::placeholders::_1)); |
| 154 int result = DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_DOWNLOADDIALOG), GetDe
sktopWindow(), |
| 155 reinterpret_cast<DLGPROC>(&DownloadDlgProc), |
| 156 reinterpret_cast<LPARAM>(callback)); |
| 157 if (result == DOWNLOAD_FAILED) |
| 104 { | 158 { |
| 105 DialogCallbackType* callback = new DialogCallbackType(std::bind(&Updater::
StartDownload, | 159 Dictionary* dict = Dictionary::GetInstance(); |
| 106 this, std::placeholders::_1)); | 160 MessageBoxW(NULL, |
| 107 int result = DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_DOWNLOADDIALOG), Get
DesktopWindow(), | 161 dict->Lookup("updater", "download-error-neterror").c_str(), |
| 108 reinterpret_cast<DLGPROC>(&DownloadDlgProc), | 162 dict->Lookup("updater", "download-error-title").c_str(), |
| 109 reinterpret_cast<LPARAM>(callback)); | 163 0); |
| 110 if (result == DOWNLOAD_FAILED) | |
| 111 { | |
| 112 Dictionary* dict = Dictionary::GetInstance(); | |
| 113 MessageBoxW(NULL, | |
| 114 dict->Lookup("updater", "download-error-neterror").c_str(), | |
| 115 dict->Lookup("updater", "download-error-title").c_str(), | |
| 116 0); | |
| 117 } | |
| 118 if (result != IDOK) | |
| 119 return; | |
| 120 } | 164 } |
| 165 if (result != IDOK) |
| 166 return; |
| 121 | 167 |
| 168 if (!InstallUpdate(tempFile)) |
| 122 { | 169 { |
| 123 UINT result = ::MsiInstallProductW(tempFile.c_str(), L"ACTION=INSTALL INST
ALLUILEVEL=2 REINSTALL=ALL REINSTALLMODE=vomus MSIENFORCEUPGRADECOMPONENTRULES=1
"); | 170 DebugLastError("Running updater failed"); |
| 124 if (result != ERROR_SUCCESS) | |
| 125 { | |
| 126 Dictionary* dict = Dictionary::GetInstance(); | |
| 127 std::wstringstream message; | |
| 128 message << dict->Lookup("updater", "download-error-runerror"); | |
| 129 message << std::endl << L"(error " << result << L")"; | |
| 130 MessageBoxW(NULL, | |
| 131 message.str().c_str(), | |
| 132 dict->Lookup("updater", "download-error-title").c_str(), | |
| 133 0); | |
| 134 | 171 |
| 135 std::stringstream error; | 172 Dictionary* dict = Dictionary::GetInstance(); |
| 136 error << "Installing update failed (error " << result << ")"; | 173 MessageBoxW(NULL, |
| 137 Debug(error.str()); | 174 dict->Lookup("updater", "download-error-runerror").c_str(), |
| 138 return; | 175 dict->Lookup("updater", "download-error-title").c_str(), |
| 139 } | 176 0); |
| 140 } | 177 } |
| 141 } | 178 } |
| 142 } | 179 } |
| 143 | 180 |
| 144 void Updater::StartDownload(HWND dialog) | 181 void Updater::StartDownload(HWND dialog) |
| 145 { | 182 { |
| 146 this->dialog = dialog; | 183 this->dialog = dialog; |
| 147 ThreadCallbackType* callback = new ThreadCallbackType(std::bind(&Updater::RunD
ownload, this)); | 184 ThreadCallbackType* callback = new ThreadCallbackType(std::bind(&Updater::RunD
ownload, this)); |
| 148 ::CreateThread(NULL, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(&RunThread), | 185 ::CreateThread(NULL, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(&RunThread), |
| 149 callback, 0, NULL); | 186 callback, 0, NULL); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 182 } | 219 } |
| 183 catch (const std::exception& e) | 220 catch (const std::exception& e) |
| 184 { | 221 { |
| 185 DebugException(e); | 222 DebugException(e); |
| 186 EndDialog(dialog, DOWNLOAD_FAILED); | 223 EndDialog(dialog, DOWNLOAD_FAILED); |
| 187 return; | 224 return; |
| 188 } | 225 } |
| 189 | 226 |
| 190 EndDialog(dialog, IDOK); | 227 EndDialog(dialog, IDOK); |
| 191 } | 228 } |
| OLD | NEW |