| Index: cloud_print/virtual_driver/win/install/setup.cc
|
| diff --git a/cloud_print/virtual_driver/win/install/setup.cc b/cloud_print/virtual_driver/win/install/setup.cc
|
| index 1b83cbb35205a8fd8349a7f1232a608d919de40b..d64ea9aebfee918a12cde377a4dfd241e1c2a60e 100644
|
| --- a/cloud_print/virtual_driver/win/install/setup.cc
|
| +++ b/cloud_print/virtual_driver/win/install/setup.cc
|
| @@ -3,6 +3,7 @@
|
| // found in the LICENSE file.
|
|
|
| #include <windows.h>
|
| +#include <setupapi.h> // Must be included after windows.h
|
| #include <winspool.h>
|
|
|
| #include "base/at_exit.h"
|
| @@ -19,14 +20,24 @@
|
| #include "cloud_print/virtual_driver/win/virtual_driver_helpers.h"
|
| #include "grit/virtual_driver_setup_resources.h"
|
|
|
| +#include <strsafe.h> // Must be after base headers to avoid deprecation
|
| + // warnings.
|
| +
|
| namespace {
|
| const wchar_t kVersionKey[] = L"pv";
|
| const wchar_t kNameKey[] = L"name";
|
| -const wchar_t kLangKey[] = L"lang";
|
| const wchar_t kNameValue[] = L"GCP Virtual Driver";
|
| -const wchar_t kLangValue[] = L"rn";
|
| +const wchar_t kPpdName[] = L"GCP-DRIVER.PPD";
|
| +const wchar_t kDriverName[] = L"MXDWDRV.DLL";
|
| +const wchar_t kUiDriverName[] = L"PS5UI.DLL";
|
| +const wchar_t kHelpName[] = L"PSCRIPT.HLP";
|
| +const wchar_t* kDependencyList[] = {kDriverName, kUiDriverName, kHelpName};
|
| +const wchar_t kUninstallRegistry[] =
|
| + L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"
|
| + L"{74AA24E0-AC50-4B28-BA46-9CF05467C9B7}";
|
| +const wchar_t kInstallerName[] = L"virtual_driver_setup.exe";
|
|
|
| -void SetRegistryKeys() {
|
| +void SetOmahaKeys() {
|
| base::win::RegKey key;
|
| if (key.Create(HKEY_LOCAL_MACHINE, cloud_print::kKeyLocation,
|
| KEY_SET_VALUE) != ERROR_SUCCESS) {
|
| @@ -49,13 +60,12 @@ void SetRegistryKeys() {
|
| }
|
|
|
| if (key.WriteValue(kVersionKey, version_string.c_str()) != ERROR_SUCCESS ||
|
| - key.WriteValue(kNameKey, kNameValue) != ERROR_SUCCESS ||
|
| - key.WriteValue(kLangKey, kLangValue) != ERROR_SUCCESS) {
|
| + key.WriteValue(kNameKey, kNameValue) != ERROR_SUCCESS) {
|
| LOG(ERROR) << "Unable to set registry keys";
|
| }
|
| }
|
|
|
| -void DeleteRegistryKeys() {
|
| +void DeleteOmahaKeys() {
|
| base::win::RegKey key;
|
| if (key.Open(HKEY_LOCAL_MACHINE, cloud_print::kKeyLocation,
|
| DELETE) != ERROR_SUCCESS) {
|
| @@ -66,25 +76,7 @@ void DeleteRegistryKeys() {
|
| }
|
| }
|
|
|
| -HRESULT GetPpdPath(FilePath* path) {
|
| - if (!PathService::Get(base::DIR_EXE, path)) {
|
| - LOG(ERROR) << "Unable to get install path.";
|
| - return ERROR_PATH_NOT_FOUND;
|
| - }
|
| - *path = path->Append(L"GCP-driver.ppd");
|
| - return S_OK;
|
| -}
|
| -
|
| -HRESULT GetPortMonitorDllPath(FilePath* path) {
|
| - if (!PathService::Get(base::DIR_EXE, path)) {
|
| - LOG(ERROR) << "Unable to get install path.";
|
| - return ERROR_PATH_NOT_FOUND;
|
| - }
|
| - *path = path->Append(cloud_print::GetPortMonitorDllName());
|
| - return S_OK;
|
| -}
|
| -
|
| -HRESULT GetPortMonitorInstallPath(FilePath* path) {
|
| +HRESULT GetNativeSystemPath(FilePath* path) {
|
| if (cloud_print::IsSystem64Bit()) {
|
| if (!PathService::Get(base::DIR_WINDOWS, path)) {
|
| return ERROR_PATH_NOT_FOUND;
|
| @@ -98,34 +90,35 @@ HRESULT GetPortMonitorInstallPath(FilePath* path) {
|
| return ERROR_PATH_NOT_FOUND;
|
| }
|
| }
|
| - *path = path->Append(cloud_print::GetPortMonitorDllName());
|
| return S_OK;
|
| }
|
|
|
| +HRESULT GetPortMonitorTargetPath(FilePath* path) {
|
| + HRESULT result = GetNativeSystemPath(path);
|
| + if (SUCCEEDED(result))
|
| + *path = path->Append(cloud_print::GetPortMonitorDllName());
|
| + return result;
|
| +}
|
| +
|
| HRESULT GetRegsvr32Path(FilePath* path) {
|
| - if (!PathService::Get(base::DIR_SYSTEM, path)) {
|
| - LOG(ERROR) << "Unable to get system path.";
|
| - return ERROR_PATH_NOT_FOUND;
|
| - }
|
| - *path = path->Append(FilePath(L"regsvr32.exe"));
|
| - return S_OK;
|
| + HRESULT result = GetNativeSystemPath(path);
|
| + if (SUCCEEDED(result))
|
| + *path = path->Append(FilePath(L"regsvr32.exe"));
|
| + return result;
|
| }
|
|
|
| -HRESULT RegisterPortMonitor(bool install) {
|
| +HRESULT RegisterPortMonitor(bool install, const FilePath& install_path) {
|
| FilePath target_path;
|
| HRESULT result = S_OK;
|
| - result = GetPortMonitorInstallPath(&target_path);
|
| + result = GetPortMonitorTargetPath(&target_path);
|
| if (!SUCCEEDED(result)) {
|
| LOG(ERROR) << "Unable to get port monitor target path.";
|
| return result;
|
| }
|
| - FilePath source_path;
|
| - result = GetPortMonitorDllPath(&source_path);
|
| - if (!SUCCEEDED(result)) {
|
| - LOG(ERROR) << "Unable to get dll source path.";
|
| - return result;
|
| - }
|
| + string16 source;
|
| + source = cloud_print::GetPortMonitorDllName();
|
| if (install) {
|
| + FilePath source_path = install_path.Append(source);
|
| if (!file_util::CopyFileW(source_path, target_path)) {
|
| LOG(ERROR) << "Unable copy port monitor dll from " <<
|
| source_path.value() << " to " << target_path.value();
|
| @@ -144,7 +137,14 @@ HRESULT RegisterPortMonitor(bool install) {
|
| if (!install) {
|
| command_line.AppendArg("/u");
|
| }
|
| - command_line.AppendArgPath(source_path);
|
| +
|
| + FilePath final_path;
|
| + if (!PathService::Get(base::DIR_SYSTEM, &final_path)) {
|
| + LOG(ERROR) << "Unable to get system path.";
|
| + return ERROR_PATH_NOT_FOUND;
|
| + }
|
| + final_path = final_path.Append(cloud_print::GetPortMonitorDllName());
|
| + command_line.AppendArgPath(final_path);
|
|
|
| base::LaunchOptions options;
|
| HANDLE process_handle;
|
| @@ -189,24 +189,63 @@ DWORDLONG GetVersionNumber() {
|
| return retval;
|
| }
|
|
|
| -HRESULT InstallPpd() {
|
| +UINT CALLBACK CabinetCallback(PVOID data,
|
| + UINT notification,
|
| + UINT_PTR param1,
|
| + UINT_PTR param2 ) {
|
| + FilePath* temp_path = reinterpret_cast<FilePath*>(data);
|
| + if (notification == SPFILENOTIFY_FILEINCABINET) {
|
| + FILE_IN_CABINET_INFO* info =
|
| + reinterpret_cast<FILE_IN_CABINET_INFO*>(param1);
|
| + for (int i = 0; i < arraysize(kDependencyList); i++) {
|
| + if (wcsstr(info->NameInCabinet, kDependencyList[i])) {
|
| + StringCchCopy(info->FullTargetName, MAX_PATH,
|
| + temp_path->Append(kDependencyList[i]).value().c_str());
|
| + return FILEOP_DOIT;
|
| + }
|
| + }
|
| +
|
| + return FILEOP_SKIP;
|
| + }
|
| + return NO_ERROR;
|
| +}
|
| +
|
| +void ReadyPpdDependencies(const FilePath& install_path) {
|
| + CORE_PRINTER_DRIVER driver;
|
| + GetCorePrinterDrivers(NULL,
|
| + NULL,
|
| + L"{D20EA372-DD35-4950-9ED8-A6335AFE79F0}",
|
| + 1,
|
| + &driver);
|
| + DWORD size = MAX_PATH;
|
| + wchar_t package_path[MAX_PATH];
|
| + GetPrinterDriverPackagePath(NULL,
|
| + NULL,
|
| + NULL,
|
| + driver.szPackageID,
|
| + package_path,
|
| + MAX_PATH,
|
| + &size);
|
| +
|
| + SetupIterateCabinet(package_path,
|
| + 0,
|
| + CabinetCallback,
|
| + const_cast<FilePath*>(&install_path));
|
| +}
|
| +
|
| +HRESULT InstallPpd(const FilePath& install_path) {
|
| DRIVER_INFO_6 driver_info = {0};
|
| HRESULT result = S_OK;
|
|
|
| // Set up paths for the files we depend on.
|
| - FilePath source_path;
|
| - FilePath driver_dir;
|
| - cloud_print::GetPrinterDriverDir(&driver_dir);
|
| - FilePath xps_path = driver_dir.Append(L"mxdwdrv.dll");
|
| - FilePath ui_path = driver_dir.Append(L"ps5ui.dll");
|
| - FilePath ui_help_path = driver_dir.Append(L"unidrv.hlp");
|
| - result = GetPpdPath(&source_path);
|
| - if (!SUCCEEDED(result)) {
|
| - return result;
|
| - }
|
| + FilePath ppd_path = install_path.Append(kPpdName);
|
| + FilePath xps_path = install_path.Append(kDriverName);
|
| + FilePath ui_path = install_path.Append(kUiDriverName);
|
| + FilePath ui_help_path = install_path.Append(kHelpName);
|
| + ReadyPpdDependencies(install_path);
|
| // None of the print API structures likes constant strings even though they
|
| // don't modify the string. const_casting is the cleanest option.
|
| - driver_info.pDataFile = const_cast<LPWSTR>(source_path.value().c_str());
|
| + driver_info.pDataFile = const_cast<LPWSTR>(ppd_path.value().c_str());
|
| driver_info.pHelpFile = const_cast<LPWSTR>(ui_help_path.value().c_str());
|
| driver_info.pDriverPath = const_cast<LPWSTR>(xps_path.value().c_str());
|
| driver_info.pConfigFile = const_cast<LPWSTR>(ui_path.value().c_str());
|
| @@ -223,19 +262,14 @@ HRESULT InstallPpd() {
|
| // Set up supported print system version. Must be 3.
|
| driver_info.cVersion = 3;
|
|
|
| - // TODO(abodenha@chromium.org) Properly handle dependencies.
|
| - // GPD files are often dependent on various Windows core drivers.
|
| - // I haven't found a reliable way to express those dependencies
|
| - // other than using an INF for installation.
|
| if (!AddPrinterDriverEx(NULL,
|
| 6,
|
| reinterpret_cast<BYTE*>(&driver_info),
|
| APD_COPY_NEW_FILES|APD_COPY_FROM_DIRECTORY)) {
|
| result = cloud_print::GetLastHResult();
|
| LOG(ERROR) << "Unable to add printer driver";
|
| - return result;
|
| }
|
| - return S_OK;
|
| + return result;
|
| }
|
|
|
| HRESULT UninstallPpd() {
|
| @@ -309,14 +343,59 @@ HRESULT UninstallPrinter(void) {
|
| return S_OK;
|
| }
|
|
|
| -HRESULT InstallVirtualDriver(void) {
|
| +void SetupUninstall(const FilePath& install_path) {
|
| + // Now write the Windows Uninstall entries
|
| + // Minimal error checking here since the install can contiunue
|
| + // if this fails.
|
| + base::win::RegKey key;
|
| + if (key.Create(HKEY_LOCAL_MACHINE, kUninstallRegistry,
|
| + KEY_SET_VALUE) != ERROR_SUCCESS) {
|
| + LOG(ERROR) << "Unable to open key";
|
| + return;
|
| + }
|
| + CommandLine uninstall_command(install_path.Append(kInstallerName));
|
| + uninstall_command.AppendArg("--uninstall");
|
| + key.WriteValue(L"UninstallString",
|
| + uninstall_command.GetCommandLineString().c_str());
|
| + key.WriteValue(L"InstallLocation", install_path.value().c_str());
|
| +
|
| +
|
| + // Get the version resource.
|
| + scoped_ptr<FileVersionInfo> version_info(
|
| + FileVersionInfo::CreateFileVersionInfoForCurrentModule());
|
| +
|
| + if (version_info.get()) {
|
| + FileVersionInfoWin* version_info_win =
|
| + static_cast<FileVersionInfoWin*>(version_info.get());
|
| + key.WriteValue(L"DisplayVersion",
|
| + version_info_win->file_version().c_str());
|
| + key.WriteValue(L"Publisher", version_info_win->company_name().c_str());
|
| + } else {
|
| + LOG(ERROR) << "Unable to get version string";
|
| + }
|
| + key.WriteValue(L"DisplayName",
|
| + cloud_print::LoadLocalString(IDS_DRIVER_NAME).c_str());
|
| + key.WriteValue(L"NoModify", 1);
|
| + key.WriteValue(L"NoRepair", 1);
|
| +}
|
| +
|
| +void CleanupUninstall() {
|
| + ::RegDeleteKey(HKEY_LOCAL_MACHINE, kUninstallRegistry);
|
| +}
|
| +
|
| +HRESULT InstallVirtualDriver(const FilePath& install_path) {
|
| HRESULT result = S_OK;
|
| - result = RegisterPortMonitor(true);
|
| + if (!file_util::CreateDirectory(install_path)) {
|
| + LOG(ERROR) << "Can't create install directory";
|
| + return ERROR_ACCESS_DENIED;
|
| + }
|
| + SetupUninstall(install_path);
|
| + result = RegisterPortMonitor(true, install_path);
|
| if (!SUCCEEDED(result)) {
|
| LOG(ERROR) << "Unable to register port monitor.";
|
| return result;
|
| }
|
| - result = InstallPpd();
|
| + result = InstallPpd(install_path);
|
| if (!SUCCEEDED(result)) {
|
| LOG(ERROR) << "Unable to install Ppd.";
|
| return result;
|
| @@ -326,11 +405,11 @@ HRESULT InstallVirtualDriver(void) {
|
| LOG(ERROR) << "Unable to install printer.";
|
| return result;
|
| }
|
| - SetRegistryKeys();
|
| + SetOmahaKeys();
|
| return S_OK;
|
| }
|
|
|
| -HRESULT UninstallVirtualDriver(void) {
|
| +HRESULT UninstallVirtualDriver(const FilePath& install_path) {
|
| HRESULT result = S_OK;
|
| result = UninstallPrinter();
|
| if (!SUCCEEDED(result)) {
|
| @@ -342,15 +421,35 @@ HRESULT UninstallVirtualDriver(void) {
|
| LOG(ERROR) << "Unable to remove Ppd.";
|
| return result;
|
| }
|
| - result = RegisterPortMonitor(false);
|
| + result = RegisterPortMonitor(false, install_path);
|
| if (!SUCCEEDED(result)) {
|
| LOG(ERROR) << "Unable to remove port monitor.";
|
| return result;
|
| }
|
| - DeleteRegistryKeys();
|
| + DeleteOmahaKeys();
|
| + file_util::Delete(install_path, true);
|
| + CleanupUninstall();
|
| return S_OK;
|
| }
|
|
|
| +HRESULT LaunchChildForUninstall() {
|
| + FilePath installer_source;
|
| + if (PathService::Get(base::FILE_EXE, &installer_source)) {
|
| + FilePath temp_path;
|
| + if (file_util::CreateTemporaryFile(&temp_path)) {
|
| + file_util::Move(installer_source, temp_path);
|
| + file_util::DeleteAfterReboot(temp_path);
|
| + CommandLine command_line(temp_path);
|
| + command_line.AppendArg("--douninstall");
|
| + base::LaunchOptions options;
|
| + if (!base::LaunchProcess(command_line, options, NULL)) {
|
| + LOG(ERROR) << "Unable to launch child uninstall.";
|
| + return ERROR_NOT_SUPPORTED;
|
| + }
|
| + }
|
| + }
|
| + return S_OK;
|
| +}
|
| } // namespace
|
|
|
| int WINAPI WinMain(__in HINSTANCE hInstance,
|
| @@ -359,11 +458,17 @@ 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("uninstall")) {
|
| - retval = UninstallVirtualDriver();
|
| - } else {
|
| - retval = InstallVirtualDriver();
|
| +
|
| + FilePath install_path;
|
| + HRESULT retval = PathService::Get(base::DIR_EXE, &install_path);
|
| + if (SUCCEEDED(retval)) {
|
| + if (CommandLine::ForCurrentProcess()->HasSwitch("douninstall")) {
|
| + retval = UninstallVirtualDriver(install_path);
|
| + } else if (CommandLine::ForCurrentProcess()->HasSwitch("uninstall")) {
|
| + retval = LaunchChildForUninstall();
|
| + } else {
|
| + retval = InstallVirtualDriver(install_path);
|
| + }
|
| }
|
| // Installer is silent by default as required by Omaha.
|
| if (CommandLine::ForCurrentProcess()->HasSwitch("verbose")) {
|
|
|