diff options
author | vitalybuka@chromium.org <vitalybuka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-12 19:46:06 +0000 |
---|---|---|
committer | vitalybuka@chromium.org <vitalybuka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-12 19:46:06 +0000 |
commit | 895ca05443d05ba7882eddec64c1ab4d7f96364f (patch) | |
tree | cf18ecc15f4471ce49d7aa102bfc2953653bdec2 /cloud_print | |
parent | f438ed8434d0653ea424b6160857406375502d26 (diff) | |
download | chromium_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.cc | 223 |
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(®svr32_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, |