summaryrefslogtreecommitdiffstats
path: root/cloud_print
diff options
context:
space:
mode:
authorvitalybuka@chromium.org <vitalybuka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-12 19:46:06 +0000
committervitalybuka@chromium.org <vitalybuka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-12 19:46:06 +0000
commit895ca05443d05ba7882eddec64c1ab4d7f96364f (patch)
treecf18ecc15f4471ce49d7aa102bfc2953653bdec2 /cloud_print
parentf438ed8434d0653ea424b6160857406375502d26 (diff)
downloadchromium_src-895ca05443d05ba7882eddec64c1ab4d7f96364f.zip
chromium_src-895ca05443d05ba7882eddec64c1ab4d7f96364f.tar.gz
chromium_src-895ca05443d05ba7882eddec64c1ab4d7f96364f.tar.bz2
Improved setup reliability.
* Register/unregister without the other install/uninstall actions. * Implicit switches for install, register, uninstall, unregistered. * Restart spooler if uninstall can't delete port monitor. BUG=169069 Review URL: https://chromiumcodereview.appspot.com/11876005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@176583 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cloud_print')
-rw-r--r--cloud_print/virtual_driver/win/install/setup.cc223
1 files changed, 138 insertions, 85 deletions
diff --git a/cloud_print/virtual_driver/win/install/setup.cc b/cloud_print/virtual_driver/win/install/setup.cc
index e9cd36c..b10d6f6 100644
--- a/cloud_print/virtual_driver/win/install/setup.cc
+++ b/cloud_print/virtual_driver/win/install/setup.cc
@@ -40,6 +40,12 @@ const wchar_t kUninstallRegistry[] =
const wchar_t kInstallerName[] = L"virtual_driver_setup.exe";
const wchar_t kGcpUrl[] = L"http://www.google.com/cloudprint";
+const char kDoUninstallSwitch[] = "douninstall";
+const char kInstallSwitch[] = "install";
+const char kRegisterSwitch[] = "register";
+const char kUninstallSwitch[] = "uninstall";
+const char kUnregisterSwitch[] = "unregister";
+
void SetGoogleUpdateKeys() {
base::win::RegKey key;
if (key.Create(HKEY_LOCAL_MACHINE, cloud_print::kKeyLocation,
@@ -80,64 +86,68 @@ void DeleteGoogleUpdateKeys() {
}
}
-HRESULT GetNativeSystemPath(FilePath* path) {
- if (cloud_print::IsSystem64Bit()) {
- if (!PathService::Get(base::DIR_WINDOWS, path)) {
- return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
- }
- // Sysnative will bypass filesystem redirection and give us
- // the location of the 64bit system32 from a 32 bit process.
- *path = path->Append(L"sysnative");
- } else {
- if (!PathService::Get(base::DIR_SYSTEM, path)) {
- LOG(ERROR) << "Unable to get system path.";
- return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
- }
+FilePath GetSystemPath(const string16& binary) {
+ FilePath path;
+ if (!PathService::Get(base::DIR_SYSTEM, &path)) {
+ LOG(ERROR) << "Unable to get system path.";
+ return path;
}
- return S_OK;
+ return path.Append(binary);
}
-HRESULT GetPortMonitorTargetPath(FilePath* path) {
- HRESULT result = GetNativeSystemPath(path);
- if (SUCCEEDED(result))
- *path = path->Append(cloud_print::GetPortMonitorDllName());
- return result;
+FilePath GetNativeSystemPath(const string16& binary) {
+ if (!cloud_print::IsSystem64Bit())
+ return GetSystemPath(binary);
+ FilePath path;
+ // Sysnative will bypass filesystem redirection and give us
+ // the location of the 64bit system32 from a 32 bit process.
+ if (!PathService::Get(base::DIR_WINDOWS, &path)) {
+ LOG(ERROR) << "Unable to get windows path.";
+ return path;
+ }
+ return path.Append(L"sysnative").Append(binary);
}
-HRESULT GetRegsvr32Path(FilePath* path) {
- HRESULT result = GetNativeSystemPath(path);
- if (SUCCEEDED(result))
- *path = path->Append(FilePath(L"regsvr32.exe"));
- return result;
+void SpoolerServiceCommand(const char* command) {
+ FilePath net_path = GetNativeSystemPath(L"net");
+ if (net_path.empty())
+ return;
+ CommandLine command_line(net_path);
+ command_line.AppendArg(command);
+ command_line.AppendArg("spooler");
+ command_line.AppendArg("/y");
+
+ base::LaunchOptions options;
+ options.wait = true;
+ options.start_hidden = true;
+ base::LaunchProcess(command_line, options, NULL);
}
HRESULT RegisterPortMonitor(bool install, const FilePath& install_path) {
- FilePath target_path;
- HRESULT result = S_OK;
- result = GetPortMonitorTargetPath(&target_path);
- if (!SUCCEEDED(result)) {
+ DCHECK(install || install_path.empty());
+ FilePath target_path =
+ GetNativeSystemPath(cloud_print::GetPortMonitorDllName());
+ if (target_path.empty()) {
LOG(ERROR) << "Unable to get port monitor target path.";
return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
}
- string16 source;
- source = cloud_print::GetPortMonitorDllName();
- FilePath source_path = install_path.Append(source);
if (install) {
- if (!file_util::CopyFileW(source_path, target_path)) {
+ FilePath source_path =
+ install_path.Append(cloud_print::GetPortMonitorDllName());
+ if (!file_util::CopyFile(source_path, target_path)) {
LOG(ERROR) << "Unable copy port monitor dll from " <<
source_path.value() << " to " << target_path.value();
return cloud_print::GetLastHResult();
}
- } else if (!file_util::PathExists(source_path)) {
+ } else if (!file_util::PathExists(target_path)) {
// Already removed. Just "succeed" silently.
return S_OK;
}
- FilePath regsvr32_path;
- result = GetRegsvr32Path(&regsvr32_path);
- if (!SUCCEEDED(result)) {
+ FilePath regsvr32_path = GetNativeSystemPath(L"regsvr32.exe");
+ if (regsvr32_path.empty()) {
LOG(ERROR) << "Can't find regsvr32.exe.";
- return result;
+ return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
}
CommandLine command_line(regsvr32_path);
@@ -146,29 +156,25 @@ HRESULT RegisterPortMonitor(bool install, const FilePath& install_path) {
command_line.AppendArg("/u");
}
- FilePath final_path;
- if (!PathService::Get(base::DIR_SYSTEM, &final_path)) {
- LOG(ERROR) << "Unable to get system path.";
- return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
- }
- final_path = final_path.Append(cloud_print::GetPortMonitorDllName());
- command_line.AppendArgPath(final_path);
+ // Use system32 path here because otherwise ::AddMonitor would fail.
+ command_line.AppendArgPath(GetSystemPath(
+ cloud_print::GetPortMonitorDllName()));
+
base::LaunchOptions options;
- HANDLE process_handle;
options.wait = true;
- if (!base::LaunchProcess(command_line, options, &process_handle)) {
+
+ base::win::ScopedHandle regsvr32_handle;
+ if (!base::LaunchProcess(command_line, options, regsvr32_handle.Receive())) {
LOG(ERROR) << "Unable to launch regsvr32.exe.";
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
- base::win::ScopedHandle scoped_process_handle(process_handle);
DWORD exit_code = S_OK;
if (install) {
- if (!GetExitCodeProcess(scoped_process_handle, &exit_code)) {
- HRESULT result = cloud_print::GetLastHResult();
+ if (!GetExitCodeProcess(regsvr32_handle, &exit_code)) {
LOG(ERROR) << "Unable to get regsvr32.exe exit code.";
- return result;
+ return cloud_print::GetLastHResult();;
}
if (exit_code != 0) {
LOG(ERROR) << "Regsvr32.exe failed with " << exit_code;
@@ -176,8 +182,14 @@ HRESULT RegisterPortMonitor(bool install, const FilePath& install_path) {
}
} else {
if (!file_util::Delete(target_path, false)) {
- LOG(ERROR) << "Unable to delete " << target_path.value();
- return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
+ SpoolerServiceCommand("stop");
+ bool deleted = file_util::Delete(target_path, false);
+ SpoolerServiceCommand("start");
+
+ if(!deleted) {
+ LOG(ERROR) << "Unable to delete " << target_path.value();
+ return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
+ }
}
}
return S_OK;
@@ -425,19 +437,15 @@ bool IsOSSupported() {
(base::win::OSInfo::GetInstance()->service_pack().major >= 3));
}
-HRESULT InstallVirtualDriver(const FilePath& install_path) {
+HRESULT RegisterVirtualDriver(const FilePath& install_path) {
HRESULT result = S_OK;
+ DCHECK(file_util::DirectoryExists(install_path));
if (!IsOSSupported()) {
LOG(ERROR) << "Requires XP SP3 or later.";
return HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION);
}
- if (!file_util::CreateDirectory(install_path)) {
- LOG(ERROR) << "Can't create install directory.";
- return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
- }
- SetupUninstall(install_path);
result = RegisterPortMonitor(true, install_path);
if (FAILED(result)) {
LOG(ERROR) << "Unable to register port monitor.";
@@ -451,7 +459,8 @@ HRESULT InstallVirtualDriver(const FilePath& install_path) {
}
result = InstallPrinter();
- if (FAILED(result)) {
+ if (FAILED(result) &&
+ result != HRESULT_FROM_WIN32(ERROR_PRINTER_ALREADY_EXISTS)) {
LOG(ERROR) << "Unable to install printer.";
return result;
}
@@ -471,12 +480,7 @@ void GetCurrentInstallPath(FilePath* install_path) {
*install_path = FilePath(install_path_value);
}
-HRESULT UninstallVirtualDriver() {
- FilePath install_path;
- GetCurrentInstallPath(&install_path);
- if (install_path.value().empty()) {
- return S_OK;
- }
+HRESULT UnregisterVirtualDriver() {
HRESULT result = S_OK;
result = UninstallPrinter();
if (FAILED(result)) {
@@ -493,14 +497,12 @@ HRESULT UninstallVirtualDriver() {
InstallPrinter();
return result;
}
- result = RegisterPortMonitor(false, install_path);
+ // The second argument is ignored if the first is false.
+ result = RegisterPortMonitor(false, FilePath());
if (FAILED(result)) {
LOG(ERROR) << "Unable to remove port monitor.";
return result;
}
- DeleteGoogleUpdateKeys();
- file_util::Delete(install_path, true);
- CleanupUninstall();
return S_OK;
}
@@ -510,7 +512,7 @@ HRESULT DoLaunchUninstall(const FilePath& installer_source, bool wait) {
file_util::CopyFile(installer_source, temp_path);
file_util::DeleteAfterReboot(temp_path);
CommandLine command_line(temp_path);
- command_line.AppendArg("--douninstall");
+ command_line.AppendArg(kDoUninstallSwitch);
base::LaunchOptions options;
options.wait = wait;
base::ProcessHandle process_handle;
@@ -558,6 +560,70 @@ HRESULT UninstallPreviousVersion() {
return S_OK;
}
+HRESULT DoUnregister() {
+ return UnregisterVirtualDriver();
+}
+
+HRESULT DoRegister(const FilePath& install_path) {
+ HRESULT result = UnregisterVirtualDriver();
+ if (FAILED(result))
+ return result;
+ return RegisterVirtualDriver(install_path);
+}
+
+HRESULT DoUninstall() {
+ FilePath install_path;
+ GetCurrentInstallPath(&install_path);
+ if (install_path.value().empty()) {
+ return S_FALSE;
+ }
+ HRESULT result = UnregisterVirtualDriver();
+ if (FAILED(result))
+ return result;
+ DeleteGoogleUpdateKeys();
+ if (file_util::DirectoryExists(install_path))
+ file_util::Delete(install_path, true);
+ CleanupUninstall();
+ return result;
+}
+
+HRESULT DoInstall(const FilePath& install_path) {
+ HRESULT result = DoUninstall();
+ if (FAILED(result)) {
+ LOG(ERROR) << "Unable to uninstall.";
+ }
+ SetupUninstall(install_path);
+ result = RegisterVirtualDriver(install_path);
+ if (FAILED(result))
+ return result;
+ SetGoogleUpdateKeys();
+ return result;
+}
+
+HRESULT ExecuteCommands() {
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+
+ FilePath exe_path;
+ if (FAILED(PathService::Get(base::DIR_EXE, &exe_path)) ||
+ !file_util::DirectoryExists(exe_path)) {
+ return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
+ }
+
+ if (command_line.HasSwitch(kDoUninstallSwitch)) {
+ return DoUninstall();
+ } else if (command_line.HasSwitch(kUninstallSwitch)) {
+ return LaunchChildForUninstall();
+ } else if (command_line.HasSwitch(kInstallSwitch)) {
+ return DoInstall(exe_path);
+ } else if (command_line.HasSwitch(kUnregisterSwitch)) {
+ return DoUnregister();
+ } else if (command_line.HasSwitch(kRegisterSwitch)) {
+ return DoRegister(exe_path);
+ }
+
+ return E_INVALIDARG;
+}
+
} // namespace
int WINAPI WinMain(__in HINSTANCE hInstance,
@@ -566,21 +632,8 @@ int WINAPI WinMain(__in HINSTANCE hInstance,
__in int nCmdShow) {
base::AtExitManager at_exit_manager;
CommandLine::Init(0, NULL);
- HRESULT retval = S_OK;
- if (CommandLine::ForCurrentProcess()->HasSwitch("douninstall")) {
- retval = UninstallVirtualDriver();
- } else if (CommandLine::ForCurrentProcess()->HasSwitch("uninstall")) {
- retval = LaunchChildForUninstall();
- } else {
- retval = UninstallPreviousVersion();
- if (SUCCEEDED(retval)) {
- FilePath install_path;
- retval = PathService::Get(base::DIR_EXE, &install_path);
- if (SUCCEEDED(retval)) {
- retval = InstallVirtualDriver(install_path);
- }
- }
- }
+ HRESULT retval = ExecuteCommands();
+
// Installer is silent by default as required by Google Update.
if (CommandLine::ForCurrentProcess()->HasSwitch("verbose")) {
cloud_print::DisplayWindowsMessage(NULL, retval,