Home | History | Annotate | Download | only in install
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <comdef.h>
      6 #include <iomanip>
      7 #include <windows.h>
      8 #include <winspool.h>
      9 #include <setupapi.h>  // Must be included after windows.h
     10 
     11 #include "base/at_exit.h"
     12 #include "base/command_line.h"
     13 #include "base/file_util.h"
     14 #include "base/file_version_info_win.h"
     15 #include "base/files/scoped_temp_dir.h"
     16 #include "base/logging.h"
     17 #include "base/path_service.h"
     18 #include "base/process/process.h"
     19 #include "base/process/launch.h"
     20 #include "base/strings/string16.h"
     21 #include "base/strings/string_util.h"
     22 #include "base/win/registry.h"
     23 #include "base/win/scoped_handle.h"
     24 #include "base/win/windows_version.h"
     25 #include "cloud_print/common/win/cloud_print_utils.h"
     26 #include "cloud_print/common/win/install_utils.h"
     27 #include "cloud_print/virtual_driver/win/virtual_driver_consts.h"
     28 #include "cloud_print/virtual_driver/win/virtual_driver_helpers.h"
     29 #include "grit/virtual_driver_setup_resources.h"
     30 
     31 #include <strsafe.h>  // Must be after base headers to avoid deprecation
     32                       // warnings.
     33 
     34 namespace cloud_print {
     35 
     36 namespace {
     37 
     38 const wchar_t kNameValue[] = L"GCP Virtual Driver";
     39 const wchar_t kUninstallId[] = L"{74AA24E0-AC50-4B28-BA46-9CF05467C9B7}";
     40 const wchar_t kInstallerName[] = L"virtual_driver_setup.exe";
     41 const wchar_t kGcpUrl[] = L"http://www.google.com/cloudprint";
     42 
     43 const wchar_t kDataFileName[] = L"gcp_driver.gpd";
     44 const wchar_t kDriverName[] = L"MXDWDRV.DLL";
     45 const wchar_t kUiDriverName[] = L"UNIDRVUI.DLL";
     46 const wchar_t kHelpName[] = L"UNIDRV.HLP";
     47 const wchar_t* kDependencyList[] = {
     48   kDriverName,
     49   kHelpName,
     50   kUiDriverName,
     51   L"STDDTYPE.GDL",
     52   L"STDNAMES.GPD",
     53   L"STDSCHEM.GDL",
     54   L"STDSCHMX.GDL",
     55   L"UNIDRV.DLL",
     56   L"UNIRES.DLL",
     57   L"XPSSVCS.DLL",
     58 };
     59 
     60 const char kDelete[] = "delete";
     61 const char kInstallSwitch[] = "install";
     62 const char kRegisterSwitch[] = "register";
     63 const char kUninstallSwitch[] = "uninstall";
     64 const char kUnregisterSwitch[] = "unregister";
     65 
     66 base::FilePath GetSystemPath(const string16& binary) {
     67   base::FilePath path;
     68   if (!PathService::Get(base::DIR_SYSTEM, &path)) {
     69     LOG(ERROR) << "Unable to get system path.";
     70     return path;
     71   }
     72   return path.Append(binary);
     73 }
     74 
     75 base::FilePath GetNativeSystemPath(const string16& binary) {
     76   if (!IsSystem64Bit())
     77     return GetSystemPath(binary);
     78   base::FilePath path;
     79   // Sysnative will bypass filesystem redirection and give us
     80   // the location of the 64bit system32 from a 32 bit process.
     81   if (!PathService::Get(base::DIR_WINDOWS, &path)) {
     82     LOG(ERROR) << "Unable to get windows path.";
     83     return path;
     84   }
     85   return path.Append(L"sysnative").Append(binary);
     86 }
     87 
     88 void SpoolerServiceCommand(const char* command) {
     89   base::FilePath net_path = GetNativeSystemPath(L"net");
     90   if (net_path.empty())
     91     return;
     92   CommandLine command_line(net_path);
     93   command_line.AppendArg(command);
     94   command_line.AppendArg("spooler");
     95   command_line.AppendArg("/y");
     96 
     97   base::LaunchOptions options;
     98   options.wait = true;
     99   options.start_hidden = true;
    100   LOG(INFO) << command_line.GetCommandLineString();
    101   base::LaunchProcess(command_line, options, NULL);
    102 }
    103 
    104 HRESULT RegisterPortMonitor(bool install, const base::FilePath& install_path) {
    105   DCHECK(install || install_path.empty());
    106   base::FilePath target_path = GetNativeSystemPath(GetPortMonitorDllName());
    107   if (target_path.empty()) {
    108     LOG(ERROR) << "Unable to get port monitor target path.";
    109     return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
    110   }
    111   if (install) {
    112     base::FilePath source_path =
    113         install_path.Append(GetPortMonitorDllName());
    114     if (!base::CopyFile(source_path, target_path)) {
    115       LOG(ERROR) << "Unable copy port monitor dll from " <<
    116           source_path.value() << " to " << target_path.value();
    117       return GetLastHResult();
    118     }
    119   } else if (!base::PathExists(target_path)) {
    120     // Already removed.  Just "succeed" silently.
    121     return S_OK;
    122   }
    123 
    124   base::FilePath regsvr32_path = GetNativeSystemPath(L"regsvr32.exe");
    125   if (regsvr32_path.empty()) {
    126     LOG(ERROR) << "Can't find regsvr32.exe.";
    127     return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
    128   }
    129 
    130   CommandLine command_line(regsvr32_path);
    131   command_line.AppendArg("/s");
    132   if (!install) {
    133     command_line.AppendArg("/u");
    134   }
    135 
    136   // Use system32 path here because otherwise ::AddMonitor would fail.
    137   command_line.AppendArgPath(GetSystemPath(GetPortMonitorDllName()));
    138 
    139   base::LaunchOptions options;
    140   options.wait = true;
    141 
    142   base::win::ScopedHandle regsvr32_handle;
    143   if (!base::LaunchProcess(command_line, options, regsvr32_handle.Receive())) {
    144     LOG(ERROR) << "Unable to launch regsvr32.exe.";
    145     return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
    146   }
    147 
    148   DWORD exit_code = S_OK;
    149   if (install) {
    150     if (!GetExitCodeProcess(regsvr32_handle, &exit_code)) {
    151       LOG(ERROR) << "Unable to get regsvr32.exe exit code.";
    152       return GetLastHResult();
    153     }
    154     if (exit_code != 0) {
    155       LOG(ERROR) << "Regsvr32.exe failed with " << exit_code;
    156       return HRESULT_FROM_WIN32(exit_code);
    157     }
    158   } else {
    159     if (!base::DeleteFile(target_path, false)) {
    160       SpoolerServiceCommand("stop");
    161       bool deleted = base::DeleteFile(target_path, false);
    162       SpoolerServiceCommand("start");
    163 
    164       if(!deleted) {
    165         LOG(ERROR) << "Unable to delete " << target_path.value();
    166         return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
    167       }
    168     }
    169   }
    170   return S_OK;
    171 }
    172 
    173 DWORDLONG GetVersionNumber() {
    174   DWORDLONG retval = 0;
    175   scoped_ptr<FileVersionInfo> version_info(
    176       FileVersionInfo::CreateFileVersionInfoForCurrentModule());
    177   if (version_info.get()) {
    178     FileVersionInfoWin* version_info_win =
    179         static_cast<FileVersionInfoWin*>(version_info.get());
    180     VS_FIXEDFILEINFO* fixed_file_info = version_info_win->fixed_file_info();
    181     retval = fixed_file_info->dwFileVersionMS;
    182     retval <<= 32;
    183     retval |= fixed_file_info->dwFileVersionLS;
    184   }
    185   return retval;
    186 }
    187 
    188 UINT CALLBACK CabinetCallback(PVOID data,
    189                               UINT notification,
    190                               UINT_PTR param1,
    191                               UINT_PTR param2) {
    192   const base::FilePath* temp_path(
    193       reinterpret_cast<const base::FilePath*>(data));
    194   if (notification == SPFILENOTIFY_FILEINCABINET) {
    195     FILE_IN_CABINET_INFO* info =
    196         reinterpret_cast<FILE_IN_CABINET_INFO*>(param1);
    197     for (int i = 0; i < arraysize(kDependencyList); i++) {
    198       base::FilePath base_name(info->NameInCabinet);
    199       base_name = base_name.BaseName();
    200       if (base::FilePath::CompareEqualIgnoreCase(base_name.value().c_str(),
    201                                                  kDependencyList[i])) {
    202         StringCchCopy(info->FullTargetName, MAX_PATH,
    203                       temp_path->Append(kDependencyList[i]).value().c_str());
    204         return FILEOP_DOIT;
    205       }
    206     }
    207     return FILEOP_SKIP;
    208   }
    209   return NO_ERROR;
    210 }
    211 
    212 void ReadyDriverDependencies(const base::FilePath& destination) {
    213   if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
    214     // GetCorePrinterDrivers and GetPrinterDriverPackagePath only exist on
    215     // Vista and later. Winspool.drv must be delayloaded so these calls don't
    216     // create problems on XP.
    217     DWORD size = MAX_PATH;
    218     wchar_t package_path[MAX_PATH] = {0};
    219     CORE_PRINTER_DRIVER driver;
    220     GetCorePrinterDrivers(NULL, NULL, L"{D20EA372-DD35-4950-9ED8-A6335AFE79F5}",
    221                           1, &driver);
    222     GetPrinterDriverPackagePath(NULL, NULL, NULL, driver.szPackageID,
    223                                 package_path, MAX_PATH, &size);
    224     SetupIterateCabinet(package_path, 0, &CabinetCallback,
    225                         &base::FilePath(destination));
    226   } else {
    227     // Driver files are in the sp3 cab.
    228     base::FilePath package_path;
    229     PathService::Get(base::DIR_WINDOWS, &package_path);
    230     package_path = package_path.Append(L"Driver Cache\\i386\\sp3.cab");
    231     SetupIterateCabinet(package_path.value().c_str(), 0, &CabinetCallback,
    232                         &base::FilePath(destination));
    233 
    234     // Copy the rest from the driver cache or system dir.
    235     base::FilePath driver_cache_path;
    236     PathService::Get(base::DIR_WINDOWS, &driver_cache_path);
    237     driver_cache_path = driver_cache_path.Append(L"Driver Cache\\i386");
    238     for (size_t i = 0; i < arraysize(kDependencyList); ++i) {
    239       base::FilePath dst_path = destination.Append(kDependencyList[i]);
    240       if (!base::PathExists(dst_path)) {
    241         base::FilePath src_path = driver_cache_path.Append(kDependencyList[i]);
    242         if (!base::PathExists(src_path))
    243           src_path = GetSystemPath(kDependencyList[i]);
    244         base::CopyFile(src_path, dst_path);
    245       }
    246     }
    247   }
    248 }
    249 
    250 HRESULT InstallDriver(const base::FilePath& install_path) {
    251   base::ScopedTempDir temp_path;
    252   if (!temp_path.CreateUniqueTempDir())
    253     return HRESULT_FROM_WIN32(ERROR_CANNOT_MAKE);
    254   ReadyDriverDependencies(temp_path.path());
    255 
    256   std::vector<string16> dependent_array;
    257   // Add all files. AddPrinterDriverEx will removes unnecessary.
    258   for (size_t i = 0; i < arraysize(kDependencyList); ++i) {
    259     base::FilePath file_path = temp_path.path().Append(kDependencyList[i]);
    260     if (base::PathExists(file_path))
    261       dependent_array.push_back(file_path.value());
    262     else
    263       LOG(WARNING) << "File is missing: " << file_path.BaseName().value();
    264   }
    265 
    266   // Set up paths for the files we depend on.
    267   base::FilePath data_file = install_path.Append(kDataFileName);
    268   base::FilePath xps_path = temp_path.path().Append(kDriverName);
    269   base::FilePath ui_path = temp_path.path().Append(kUiDriverName);
    270   base::FilePath ui_help_path = temp_path.path().Append(kHelpName);
    271 
    272   if (!base::PathExists(xps_path)) {
    273     SetGoogleUpdateError(kGoogleUpdateProductId,
    274                          LoadLocalString(IDS_ERROR_NO_XPS));
    275     return HRESULT_FROM_WIN32(ERROR_BAD_DRIVER);
    276   }
    277 
    278   DRIVER_INFO_6 driver_info = {0};
    279   // Set up supported print system version.  Must be 3.
    280   driver_info.cVersion = 3;
    281 
    282   // None of the print API structures likes constant strings even though they
    283   // don't modify the string.  const_casting is the cleanest option.
    284   driver_info.pDataFile = const_cast<LPWSTR>(data_file.value().c_str());
    285   driver_info.pHelpFile = const_cast<LPWSTR>(ui_help_path.value().c_str());
    286   driver_info.pDriverPath = const_cast<LPWSTR>(xps_path.value().c_str());
    287   driver_info.pConfigFile = const_cast<LPWSTR>(ui_path.value().c_str());
    288 
    289   string16 dependent_files(JoinString(dependent_array, L'\n'));
    290   dependent_files.push_back(L'\n');
    291   std::replace(dependent_files.begin(), dependent_files.end(), L'\n', L'\0');
    292   driver_info.pDependentFiles = &dependent_files[0];
    293 
    294   // Set up user visible strings.
    295   string16 manufacturer = LoadLocalString(IDS_GOOGLE);
    296   driver_info.pszMfgName = const_cast<LPWSTR>(manufacturer.c_str());
    297   driver_info.pszProvider = const_cast<LPWSTR>(manufacturer.c_str());
    298   driver_info.pszOEMUrl = const_cast<LPWSTR>(kGcpUrl);
    299   driver_info.dwlDriverVersion = GetVersionNumber();
    300   string16 driver_name = LoadLocalString(IDS_DRIVER_NAME);
    301   driver_info.pName = const_cast<LPWSTR>(driver_name.c_str());
    302 
    303   if (!::AddPrinterDriverEx(NULL, 6, reinterpret_cast<BYTE*>(&driver_info),
    304                             APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY)) {
    305     LOG(ERROR) << "Unable to add printer driver";
    306     return GetLastHResult();
    307   }
    308   return S_OK;
    309 }
    310 
    311 HRESULT UninstallDriver() {
    312   int tries = 3;
    313   string16 driver_name = LoadLocalString(IDS_DRIVER_NAME);
    314   while (!DeletePrinterDriverEx(NULL,
    315                                 NULL,
    316                                 const_cast<LPWSTR>(driver_name.c_str()),
    317                                 DPD_DELETE_UNUSED_FILES,
    318                                 0) && tries > 0) {
    319     if (GetLastError() == ERROR_UNKNOWN_PRINTER_DRIVER) {
    320       LOG(WARNING) << "Print driver is already uninstalled.";
    321       return S_OK;
    322     }
    323     // After deleting the printer it can take a few seconds before
    324     // the driver is free for deletion.  Retry a few times before giving up.
    325     LOG(WARNING) << "Attempt to delete printer driver failed.  Retrying.";
    326     tries--;
    327     Sleep(2000);
    328   }
    329   if (tries <= 0) {
    330     HRESULT result = GetLastHResult();
    331     LOG(ERROR) << "Unable to delete printer driver.";
    332     return result;
    333   }
    334   return S_OK;
    335 }
    336 
    337 HRESULT InstallPrinter(void) {
    338   PRINTER_INFO_2 printer_info = {0};
    339 
    340   // None of the print API structures likes constant strings even though they
    341   // don't modify the string.  const_casting is the cleanest option.
    342   string16 driver_name = LoadLocalString(IDS_DRIVER_NAME);
    343   printer_info.pDriverName = const_cast<LPWSTR>(driver_name.c_str());
    344   printer_info.pPrinterName = const_cast<LPWSTR>(driver_name.c_str());
    345   printer_info.pComment =  const_cast<LPWSTR>(driver_name.c_str());
    346   printer_info.pLocation = const_cast<LPWSTR>(kGcpUrl);
    347   string16 port_name;
    348   printer_info.pPortName = const_cast<LPWSTR>(kPortName);
    349   printer_info.Attributes = PRINTER_ATTRIBUTE_DIRECT|PRINTER_ATTRIBUTE_LOCAL;
    350   printer_info.pPrintProcessor = L"winprint";
    351   HANDLE handle = AddPrinter(NULL, 2, reinterpret_cast<BYTE*>(&printer_info));
    352   if (handle == NULL) {
    353     HRESULT result = GetLastHResult();
    354     LOG(ERROR) << "Unable to add printer";
    355     return result;
    356   }
    357   ClosePrinter(handle);
    358   return S_OK;
    359 }
    360 
    361 HRESULT UninstallPrinter(void) {
    362   HANDLE handle = NULL;
    363   PRINTER_DEFAULTS printer_defaults = {0};
    364   printer_defaults.DesiredAccess = PRINTER_ALL_ACCESS;
    365   string16 driver_name = LoadLocalString(IDS_DRIVER_NAME);
    366   if (!OpenPrinter(const_cast<LPWSTR>(driver_name.c_str()),
    367                    &handle,
    368                    &printer_defaults)) {
    369     // If we can't open the printer, it was probably already removed.
    370     LOG(WARNING) << "Unable to open printer";
    371     return S_OK;
    372   }
    373   if (!DeletePrinter(handle)) {
    374     HRESULT result = GetLastHResult();
    375     LOG(ERROR) << "Unable to delete printer";
    376     ClosePrinter(handle);
    377     return result;
    378   }
    379   ClosePrinter(handle);
    380   return S_OK;
    381 }
    382 
    383 bool IsOSSupported() {
    384   // We don't support XP service pack 2 or older.
    385   base::win::Version version = base::win::GetVersion();
    386   return (version > base::win::VERSION_XP) ||
    387       ((version == base::win::VERSION_XP) &&
    388        (base::win::OSInfo::GetInstance()->service_pack().major >= 3));
    389 }
    390 
    391 HRESULT RegisterVirtualDriver(const base::FilePath& install_path) {
    392   HRESULT result = S_OK;
    393 
    394   DCHECK(base::DirectoryExists(install_path));
    395   if (!IsOSSupported()) {
    396     LOG(ERROR) << "Requires XP SP3 or later.";
    397     return HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION);
    398   }
    399 
    400   result = InstallDriver(install_path);
    401   if (FAILED(result)) {
    402     LOG(ERROR) << "Unable to install driver.";
    403     return result;
    404   }
    405 
    406   result = RegisterPortMonitor(true, install_path);
    407   if (FAILED(result)) {
    408     LOG(ERROR) << "Unable to register port monitor.";
    409     return result;
    410   }
    411 
    412   result = InstallPrinter();
    413   if (FAILED(result) &&
    414       result != HRESULT_FROM_WIN32(ERROR_PRINTER_ALREADY_EXISTS)) {
    415     LOG(ERROR) << "Unable to install printer.";
    416     return result;
    417   }
    418   return S_OK;
    419 }
    420 
    421 HRESULT TryUnregisterVirtualDriver() {
    422   HRESULT result = S_OK;
    423   result = UninstallPrinter();
    424   if (FAILED(result)) {
    425     LOG(ERROR) << "Unable to delete printer.";
    426     return result;
    427   }
    428   result = UninstallDriver();
    429   if (FAILED(result)) {
    430     LOG(ERROR) << "Unable to remove driver.";
    431     return result;
    432   }
    433   // The second argument is ignored if the first is false.
    434   result = RegisterPortMonitor(false, base::FilePath());
    435   if (FAILED(result)) {
    436     LOG(ERROR) << "Unable to remove port monitor.";
    437     return result;
    438   }
    439   return S_OK;
    440 }
    441 
    442 HRESULT UnregisterVirtualDriver() {
    443   HRESULT hr = S_FALSE;
    444   for (int i = 0; i < 2; ++i) {
    445     hr = TryUnregisterVirtualDriver();
    446     if (SUCCEEDED(hr)) {
    447       break;
    448     }
    449     // Restart spooler and try again.
    450     SpoolerServiceCommand("stop");
    451     SpoolerServiceCommand("start");
    452   }
    453   return hr;
    454 }
    455 
    456 HRESULT DoUninstall() {
    457   DeleteGoogleUpdateKeys(kGoogleUpdateProductId);
    458   HRESULT result = UnregisterVirtualDriver();
    459   if (FAILED(result))
    460     return result;
    461   DeleteUninstallKey(kUninstallId);
    462   DeleteProgramDir(kDelete);
    463   return S_OK;
    464 }
    465 
    466 HRESULT DoUnregister() {
    467   return UnregisterVirtualDriver();
    468 }
    469 
    470 HRESULT DoRegister(const base::FilePath& install_path) {
    471   HRESULT result = UnregisterVirtualDriver();
    472   if (FAILED(result))
    473     return result;
    474   return RegisterVirtualDriver(install_path);
    475 }
    476 
    477 HRESULT DoDelete(const base::FilePath& install_path) {
    478   if (install_path.value().empty())
    479     return E_INVALIDARG;
    480   if (!base::DirectoryExists(install_path))
    481     return S_FALSE;
    482   Sleep(5000);  // Give parent some time to exit.
    483   return base::DeleteFile(install_path, true) ? S_OK : E_FAIL;
    484 }
    485 
    486 HRESULT DoInstall(const base::FilePath& install_path) {
    487   HRESULT result = UnregisterVirtualDriver();
    488   if (FAILED(result)) {
    489     LOG(ERROR) << "Unable to unregister.";
    490     return result;
    491   }
    492   base::FilePath old_install_path = GetInstallLocation(kUninstallId);
    493   if (!old_install_path.value().empty() &&
    494       install_path != old_install_path) {
    495     if (base::DirectoryExists(old_install_path))
    496       base::DeleteFile(old_install_path, true);
    497   }
    498   CreateUninstallKey(kUninstallId, LoadLocalString(IDS_DRIVER_NAME),
    499                      kUninstallSwitch);
    500   result = RegisterVirtualDriver(install_path);
    501   if (FAILED(result))
    502     return result;
    503   SetGoogleUpdateKeys(kGoogleUpdateProductId, kNameValue);
    504   return result;
    505 }
    506 
    507 HRESULT ExecuteCommands() {
    508   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    509 
    510   base::FilePath exe_path;
    511   if (FAILED(PathService::Get(base::DIR_EXE, &exe_path)) ||
    512       !base::DirectoryExists(exe_path)) {
    513     return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
    514   }
    515 
    516   if (command_line.HasSwitch(kDelete)) {
    517     return DoDelete(command_line.GetSwitchValuePath(kDelete));
    518   } else if (command_line.HasSwitch(kUninstallSwitch)) {
    519     return DoUninstall();
    520   } else if (command_line.HasSwitch(kInstallSwitch)) {
    521     return DoInstall(exe_path);
    522   } else if (command_line.HasSwitch(kUnregisterSwitch)) {
    523     return DoUnregister();
    524   } else if (command_line.HasSwitch(kRegisterSwitch)) {
    525     return DoRegister(exe_path);
    526   }
    527 
    528   return E_INVALIDARG;
    529 }
    530 
    531 }  // namespace
    532 
    533 }  // namespace cloud_print
    534 
    535 int WINAPI WinMain(__in  HINSTANCE hInstance,
    536                    __in  HINSTANCE hPrevInstance,
    537                    __in  LPSTR lpCmdLine,
    538                    __in  int nCmdShow) {
    539   base::AtExitManager at_exit_manager;
    540   CommandLine::Init(0, NULL);
    541   HRESULT retval = cloud_print::ExecuteCommands();
    542 
    543   LOG(INFO) << _com_error(retval).ErrorMessage() << " HRESULT=0x" <<
    544                std::setbase(16) << retval;
    545 
    546   // Installer is silent by default as required by Google Update.
    547   if (CommandLine::ForCurrentProcess()->HasSwitch("verbose")) {
    548     cloud_print::DisplayWindowsMessage(NULL, retval,
    549         cloud_print::LoadLocalString(IDS_DRIVER_NAME));
    550   }
    551   return retval;
    552 }
    553