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 |