Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: src/engine/Updater.cpp

Issue 10920006: Expect MSI installers (Closed)
Patch Set: Separate function to run updater, using msiexec now Created June 13, 2013, 2:32 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « AdblockPlusEngine.vcxproj ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/engine/Updater.cpp
===================================================================
--- a/src/engine/Updater.cpp
+++ b/src/engine/Updater.cpp
@@ -1,18 +1,18 @@
#include <functional>
#include <memory>
#include <sstream>
#include <Windows.h>
-#include <Msi.h>
#include <AdblockPlus/FileSystem.h>
#include <AdblockPlus/WebRequest.h>
+#include "../shared/AutoHandle.h"
#include "../shared/Dictionary.h"
#include "../shared/Utils.h"
#include "Debug.h"
#include "Resource.h"
#include "Updater.h"
namespace
{
@@ -80,68 +80,105 @@ namespace
}
DWORD RunThread(LPVOID param)
{
std::auto_ptr<ThreadCallbackType> callback(reinterpret_cast<ThreadCallbackType*>(param));
(*callback)();
return 0;
}
+
+ std::wstring EscapeCommandLineArg(const std::wstring& arg)
+ {
+ // This does the inverse of CommandLineToArgvW(). See
+ // http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx for
+ // a description of the rules - the backslash rules are very non-obvious.
+ std::wstring result = arg;
+ size_t pos = arg.find(L'"');
+ while (pos != std::wstring::npos)
+ {
+ // Protect the quotation mark
+ result.insert(pos, 1, L'\\');
+ pos++;
+
+ // Protect any of the preceding backslashes
+ for (int offset = -2; pos + offset >= 0 && result[pos + offset] == L'\\'; offset -= 2)
+ {
+ result.insert(pos + offset, 1, L'\\');
+ pos++;
+ }
+
+ // Find next quotation mark
+ pos = arg.find(L'"', pos);
+ }
+ return L'"' + result + L'"';
+ }
+
+ BOOL InstallUpdate(const std::wstring& path)
+ {
+ WCHAR sysDir[MAX_PATH];
+ UINT sysDirLen = GetSystemDirectoryW(sysDir, sizeof(sysDir) / sizeof(sysDir[0]));
+ if (sysDirLen == 0)
+ return false;
+
+ std::wstring msiexec = std::wstring(sysDir, sysDirLen) + L"\\msiexec.exe";
+
+ std::wstring params = L"/i " + EscapeCommandLineArg(path)
+ + L" ACTION=INSTALL INSTALLUILEVEL=2 REINSTALL=ALL"
+ L" REINSTALLMODE=vomus MSIENFORCEUPGRADECOMPONENTRULES=1";
+
+ HINSTANCE instance = ShellExecuteW(NULL, L"runas", msiexec.c_str(), params.c_str(), NULL, SW_HIDE);
+ if (reinterpret_cast<int>(instance) <= 32)
+ return false;
+
+ // As far as we are concerned everything is fine - MSI service will handle
+ // further errors.
+ return true;
+ }
}
Updater::Updater(AdblockPlus::JsEnginePtr jsEngine, const std::string& url)
: jsEngine(jsEngine), url(url), tempFile(GetAppDataPath() + L"\\update.msi")
{
}
void Updater::Update()
{
Debug("Update available: " + url);
if (DialogBox(NULL, MAKEINTRESOURCE(IDD_UPDATEDIALOG), GetDesktopWindow(),
reinterpret_cast<DLGPROC>(&UpdateDlgProc)) == IDOK)
{
Debug("User accepted update");
+ DialogCallbackType* callback = new DialogCallbackType(std::bind(&Updater::StartDownload,
+ this, std::placeholders::_1));
+ int result = DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_DOWNLOADDIALOG), GetDesktopWindow(),
+ reinterpret_cast<DLGPROC>(&DownloadDlgProc),
+ reinterpret_cast<LPARAM>(callback));
+ if (result == DOWNLOAD_FAILED)
{
- DialogCallbackType* callback = new DialogCallbackType(std::bind(&Updater::StartDownload,
- this, std::placeholders::_1));
- int result = DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_DOWNLOADDIALOG), GetDesktopWindow(),
- reinterpret_cast<DLGPROC>(&DownloadDlgProc),
- reinterpret_cast<LPARAM>(callback));
- if (result == DOWNLOAD_FAILED)
- {
- Dictionary* dict = Dictionary::GetInstance();
- MessageBoxW(NULL,
- dict->Lookup("updater", "download-error-neterror").c_str(),
- dict->Lookup("updater", "download-error-title").c_str(),
- 0);
- }
- if (result != IDOK)
- return;
+ Dictionary* dict = Dictionary::GetInstance();
+ MessageBoxW(NULL,
+ dict->Lookup("updater", "download-error-neterror").c_str(),
+ dict->Lookup("updater", "download-error-title").c_str(),
+ 0);
}
+ if (result != IDOK)
+ return;
+ if (!InstallUpdate(tempFile))
{
- UINT result = ::MsiInstallProductW(tempFile.c_str(), L"ACTION=INSTALL INSTALLUILEVEL=2 REINSTALL=ALL REINSTALLMODE=vomus MSIENFORCEUPGRADECOMPONENTRULES=1");
- if (result != ERROR_SUCCESS)
- {
- Dictionary* dict = Dictionary::GetInstance();
- std::wstringstream message;
- message << dict->Lookup("updater", "download-error-runerror");
- message << std::endl << L"(error " << result << L")";
- MessageBoxW(NULL,
- message.str().c_str(),
- dict->Lookup("updater", "download-error-title").c_str(),
- 0);
+ DebugLastError("Running updater failed");
- std::stringstream error;
- error << "Installing update failed (error " << result << ")";
- Debug(error.str());
- return;
- }
+ Dictionary* dict = Dictionary::GetInstance();
+ MessageBoxW(NULL,
+ dict->Lookup("updater", "download-error-runerror").c_str(),
+ dict->Lookup("updater", "download-error-title").c_str(),
+ 0);
}
}
}
void Updater::StartDownload(HWND dialog)
{
this->dialog = dialog;
ThreadCallbackType* callback = new ThreadCallbackType(std::bind(&Updater::RunDownload, this));
« no previous file with comments | « AdblockPlusEngine.vcxproj ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld