Left: | ||
Right: |
LEFT | RIGHT |
---|---|
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 |
104 { | 152 DialogCallbackType* callback = new DialogCallbackType(std::bind(&Updater::St artDownload, |
Felix Dahlke
2013/06/11 10:07:52
I presume the two blocks are to avoid conflicts be
Wladimir Palant
2013/06/11 14:42:10
I would rather have distinct scopes for these two
| |
105 DialogCallbackType* callback = new DialogCallbackType(std::bind(&Updater:: StartDownload, | 153 this, std::placeholders::_1)); |
106 this, std::placeholders::_1)); | 154 int result = DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_DOWNLOADDIALOG), GetDe sktopWindow(), |
107 int result = DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_DOWNLOADDIALOG), Get DesktopWindow(), | 155 reinterpret_cast<DLGPROC>(&DownloadDlgProc), |
108 reinterpret_cast<DLGPROC>(&DownloadDlgProc), | 156 reinterpret_cast<LPARAM>(callback)); |
109 reinterpret_cast<LPARAM>(callback)); | 157 if (result == DOWNLOAD_FAILED) |
110 if (result == DOWNLOAD_FAILED) | 158 { |
111 { | 159 Dictionary* dict = Dictionary::GetInstance(); |
112 Dictionary* dict = Dictionary::GetInstance(); | 160 MessageBoxW(NULL, |
113 MessageBoxW(NULL, | 161 dict->Lookup("updater", "download-error-neterror").c_str(), |
114 dict->Lookup("updater", "download-error-neterror").c_str(), | 162 dict->Lookup("updater", "download-error-title").c_str(), |
115 dict->Lookup("updater", "download-error-title").c_str(), | 163 0); |
116 0); | 164 } |
117 } | 165 if (result != IDOK) |
118 if (result != IDOK) | 166 return; |
119 return; | 167 |
120 } | 168 if (!InstallUpdate(tempFile)) |
121 | 169 { |
122 { | 170 DebugLastError("Running updater failed"); |
123 UINT result = ::MsiInstallProductW(tempFile.c_str(), L"ACTION=INSTALL INST ALLUILEVEL=2"); | 171 |
Oleksandr
2013/06/10 16:47:56
Wouldn't it be better just to launch like "msiexec
Wladimir Palant
2013/06/11 04:29:56
MsiInstallProduct is IMHO a much cleaner solution
Felix Dahlke
2013/06/11 10:07:52
As long as "update.msi" is hardcoded above we'd ne
Oleksandr
2013/06/11 10:24:49
That's my point. Stuff happens, and maybe for some
Felix Dahlke
2013/06/11 10:28:05
Couldn't we just ship an exe with the msi and exec
Wladimir Palant
2013/06/11 14:42:10
I really don't see why we would need a plan b (one
Felix Dahlke
2013/06/12 13:03:40
I'd vote for two functions then :)
| |
124 if (result != ERROR_SUCCESS) | 172 Dictionary* dict = Dictionary::GetInstance(); |
125 { | 173 MessageBoxW(NULL, |
126 Dictionary* dict = Dictionary::GetInstance(); | 174 dict->Lookup("updater", "download-error-runerror").c_str(), |
127 std::wstringstream message; | 175 dict->Lookup("updater", "download-error-title").c_str(), |
128 message << dict->Lookup("updater", "download-error-runerror"); | 176 0); |
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 | |
135 std::stringstream error; | |
136 error << "Installing update failed (error " << result << ")"; | |
137 Debug(error.str()); | |
138 return; | |
139 } | |
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 } |
LEFT | RIGHT |