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 <windows.h> 6 #include <setupapi.h> // Must be included after windows.h 7 #include <winspool.h> 8 #include <iomanip> 9 10 #include "base/at_exit.h" 11 #include "base/command_line.h" 12 #include "base/file_version_info_win.h" 13 #include "base/files/file_util.h" 14 #include "base/files/scoped_temp_dir.h" 15 #include "base/logging.h" 16 #include "base/path_service.h" 17 #include "base/process/launch.h" 18 #include "base/process/process.h" 19 #include "base/strings/string16.h" 20 #include "base/strings/string_util.h" 21 #include "base/win/registry.h" 22 #include "base/win/scoped_handle.h" 23 #include "base/win/windows_version.h" 24 #include "cloud_print/common/win/cloud_print_utils.h" 25 #include "cloud_print/common/win/install_utils.h" 26 #include "cloud_print/virtual_driver/win/virtual_driver_consts.h" 27 #include "cloud_print/virtual_driver/win/virtual_driver_helpers.h" 28 #include "grit/virtual_driver_setup_resources.h" 29 30 #include <strsafe.h> // Must be after base headers to avoid deprecation 31 // warnings. 32 33 namespace cloud_print { 34 35 namespace { 36 37 const wchar_t kNameValue[] = L"GCP Virtual Driver"; 38 const wchar_t kUninstallId[] = L"{74AA24E0-AC50-4B28-BA46-9CF05467C9B7}"; 39 const wchar_t kInstallerName[] = L"virtual_driver_setup.exe"; 40 const wchar_t kGcpUrl[] = L"http://www.google.com/cloudprint"; 41 42 const wchar_t kDataFileName[] = L"gcp_driver.gpd"; 43 const wchar_t kDriverName[] = L"MXDWDRV.DLL"; 44 const wchar_t kUiDriverName[] = L"UNIDRVUI.DLL"; 45 const wchar_t kHelpName[] = L"UNIDRV.HLP"; 46 const wchar_t* kDependencyList[] = { 47 kDriverName, 48 kHelpName, 49 kUiDriverName, 50 L"STDDTYPE.GDL", 51 L"STDNAMES.GPD", 52 L"STDSCHEM.GDL", 53 L"STDSCHMX.GDL", 54 L"UNIDRV.DLL", 55 L"UNIRES.DLL", 56 L"XPSSVCS.DLL", 57 }; 58 59 const char kDelete[] = "delete"; 60 const char kInstallSwitch[] = "install"; 61 const char kRegisterSwitch[] = "register"; 62 const char kUninstallSwitch[] = "uninstall"; 63 const char kUnregisterSwitch[] = "unregister"; 64 65 base::FilePath GetSystemPath(const base::string16& binary) { 66 base::FilePath path; 67 if (!PathService::Get(base::DIR_SYSTEM, &path)) { 68 LOG(ERROR) << "Unable to get system path."; 69 return path; 70 } 71 return path.Append(binary); 72 } 73 74 base::FilePath GetNativeSystemPath(const base::string16& binary) { 75 if (!IsSystem64Bit()) 76 return GetSystemPath(binary); 77 base::FilePath path; 78 // Sysnative will bypass filesystem redirection and give us 79 // the location of the 64bit system32 from a 32 bit process. 80 if (!PathService::Get(base::DIR_WINDOWS, &path)) { 81 LOG(ERROR) << "Unable to get windows path."; 82 return path; 83 } 84 return path.Append(L"sysnative").Append(binary); 85 } 86 87 void SpoolerServiceCommand(const char* command) { 88 base::FilePath net_path = GetNativeSystemPath(L"net"); 89 if (net_path.empty()) 90 return; 91 CommandLine command_line(net_path); 92 command_line.AppendArg(command); 93 command_line.AppendArg("spooler"); 94 command_line.AppendArg("/y"); 95 96 base::LaunchOptions options; 97 options.wait = true; 98 options.start_hidden = true; 99 VLOG(0) << command_line.GetCommandLineString(); 100 base::LaunchProcess(command_line, options, NULL); 101 } 102 103 HRESULT RegisterPortMonitor(bool install, const base::FilePath& install_path) { 104 DCHECK(install || install_path.empty()); 105 base::FilePath target_path = GetNativeSystemPath(GetPortMonitorDllName()); 106 if (target_path.empty()) { 107 LOG(ERROR) << "Unable to get port monitor target path."; 108 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); 109 } 110 if (install) { 111 base::FilePath source_path = 112 install_path.Append(GetPortMonitorDllName()); 113 if (!base::CopyFile(source_path, target_path)) { 114 LOG(ERROR) << "Unable copy port monitor dll from " << 115 source_path.value() << " to " << target_path.value(); 116 return GetLastHResult(); 117 } 118 } else if (!base::PathExists(target_path)) { 119 // Already removed. Just "succeed" silently. 120 return S_OK; 121 } 122 123 base::FilePath regsvr32_path = GetNativeSystemPath(L"regsvr32.exe"); 124 if (regsvr32_path.empty()) { 125 LOG(ERROR) << "Can't find regsvr32.exe."; 126 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); 127 } 128 129 CommandLine command_line(regsvr32_path); 130 command_line.AppendArg("/s"); 131 if (!install) { 132 command_line.AppendArg("/u"); 133 } 134 135 // Use system32 path here because otherwise ::AddMonitor would fail. 136 command_line.AppendArgPath(GetSystemPath(GetPortMonitorDllName())); 137 138 base::LaunchOptions options; 139 options.wait = true; 140 141 base::win::ScopedHandle regsvr32_handle; 142 if (!base::LaunchProcess(command_line.GetCommandLineString(), options, 143 ®svr32_handle)) { 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.Get(), &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 base::FilePath destination_copy(destination); 214 if (base::win::GetVersion() >= base::win::VERSION_VISTA) { 215 // GetCorePrinterDrivers and GetPrinterDriverPackagePath only exist on 216 // Vista and later. Winspool.drv must be delayloaded so these calls don't 217 // create problems on XP. 218 DWORD size = MAX_PATH; 219 wchar_t package_path[MAX_PATH] = {0}; 220 CORE_PRINTER_DRIVER driver; 221 GetCorePrinterDrivers(NULL, NULL, L"{D20EA372-DD35-4950-9ED8-A6335AFE79F5}", 222 1, &driver); 223 GetPrinterDriverPackagePath(NULL, NULL, NULL, driver.szPackageID, 224 package_path, MAX_PATH, &size); 225 SetupIterateCabinet(package_path, 0, &CabinetCallback, &destination_copy); 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 &destination_copy); 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<base::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 return HRESULT_FROM_WIN32(ERROR_BAD_DRIVER); 274 } 275 276 DRIVER_INFO_6 driver_info = {0}; 277 // Set up supported print system version. Must be 3. 278 driver_info.cVersion = 3; 279 280 // None of the print API structures likes constant strings even though they 281 // don't modify the string. const_casting is the cleanest option. 282 driver_info.pDataFile = const_cast<LPWSTR>(data_file.value().c_str()); 283 driver_info.pHelpFile = const_cast<LPWSTR>(ui_help_path.value().c_str()); 284 driver_info.pDriverPath = const_cast<LPWSTR>(xps_path.value().c_str()); 285 driver_info.pConfigFile = const_cast<LPWSTR>(ui_path.value().c_str()); 286 287 base::string16 dependent_files(JoinString(dependent_array, L'\n')); 288 dependent_files.push_back(L'\n'); 289 std::replace(dependent_files.begin(), dependent_files.end(), L'\n', L'\0'); 290 driver_info.pDependentFiles = &dependent_files[0]; 291 292 // Set up user visible strings. 293 base::string16 manufacturer = LoadLocalString(IDS_GOOGLE); 294 driver_info.pszMfgName = const_cast<LPWSTR>(manufacturer.c_str()); 295 driver_info.pszProvider = const_cast<LPWSTR>(manufacturer.c_str()); 296 driver_info.pszOEMUrl = const_cast<LPWSTR>(kGcpUrl); 297 driver_info.dwlDriverVersion = GetVersionNumber(); 298 base::string16 driver_name = LoadLocalString(IDS_DRIVER_NAME); 299 driver_info.pName = const_cast<LPWSTR>(driver_name.c_str()); 300 301 if (!::AddPrinterDriverEx(NULL, 6, reinterpret_cast<BYTE*>(&driver_info), 302 APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY)) { 303 LOG(ERROR) << "Unable to add printer driver"; 304 return GetLastHResult(); 305 } 306 return S_OK; 307 } 308 309 HRESULT UninstallDriver() { 310 int tries = 3; 311 base::string16 driver_name = LoadLocalString(IDS_DRIVER_NAME); 312 while (!DeletePrinterDriverEx(NULL, 313 NULL, 314 const_cast<LPWSTR>(driver_name.c_str()), 315 DPD_DELETE_UNUSED_FILES, 316 0) && tries > 0) { 317 if (GetLastError() == ERROR_UNKNOWN_PRINTER_DRIVER) { 318 LOG(WARNING) << "Print driver is already uninstalled."; 319 return S_OK; 320 } 321 // After deleting the printer it can take a few seconds before 322 // the driver is free for deletion. Retry a few times before giving up. 323 LOG(WARNING) << "Attempt to delete printer driver failed. Retrying."; 324 tries--; 325 Sleep(2000); 326 } 327 if (tries <= 0) { 328 HRESULT result = GetLastHResult(); 329 LOG(ERROR) << "Unable to delete printer driver."; 330 return result; 331 } 332 return S_OK; 333 } 334 335 HRESULT InstallPrinter(void) { 336 PRINTER_INFO_2 printer_info = {0}; 337 338 // None of the print API structures likes constant strings even though they 339 // don't modify the string. const_casting is the cleanest option. 340 base::string16 driver_name = LoadLocalString(IDS_DRIVER_NAME); 341 printer_info.pDriverName = const_cast<LPWSTR>(driver_name.c_str()); 342 printer_info.pPrinterName = const_cast<LPWSTR>(driver_name.c_str()); 343 printer_info.pComment = const_cast<LPWSTR>(driver_name.c_str()); 344 printer_info.pLocation = const_cast<LPWSTR>(kGcpUrl); 345 base::string16 port_name; 346 printer_info.pPortName = const_cast<LPWSTR>(kPortName); 347 printer_info.Attributes = PRINTER_ATTRIBUTE_DIRECT|PRINTER_ATTRIBUTE_LOCAL; 348 printer_info.pPrintProcessor = const_cast<LPWSTR>(L"winprint"); 349 HANDLE handle = AddPrinter(NULL, 2, reinterpret_cast<BYTE*>(&printer_info)); 350 if (handle == NULL) { 351 HRESULT result = GetLastHResult(); 352 LOG(ERROR) << "Unable to add printer"; 353 return result; 354 } 355 ClosePrinter(handle); 356 return S_OK; 357 } 358 359 HRESULT UninstallPrinter(void) { 360 HANDLE handle = NULL; 361 PRINTER_DEFAULTS printer_defaults = {0}; 362 printer_defaults.DesiredAccess = PRINTER_ALL_ACCESS; 363 base::string16 driver_name = LoadLocalString(IDS_DRIVER_NAME); 364 if (!OpenPrinter(const_cast<LPWSTR>(driver_name.c_str()), 365 &handle, 366 &printer_defaults)) { 367 // If we can't open the printer, it was probably already removed. 368 LOG(WARNING) << "Unable to open printer"; 369 return S_OK; 370 } 371 if (!DeletePrinter(handle)) { 372 HRESULT result = GetLastHResult(); 373 LOG(ERROR) << "Unable to delete printer"; 374 ClosePrinter(handle); 375 return result; 376 } 377 ClosePrinter(handle); 378 return S_OK; 379 } 380 381 bool IsOSSupported() { 382 // We don't support XP service pack 2 or older. 383 base::win::Version version = base::win::GetVersion(); 384 return (version > base::win::VERSION_XP) || 385 ((version == base::win::VERSION_XP) && 386 (base::win::OSInfo::GetInstance()->service_pack().major >= 3)); 387 } 388 389 HRESULT RegisterVirtualDriver(const base::FilePath& install_path) { 390 HRESULT result = S_OK; 391 392 DCHECK(base::DirectoryExists(install_path)); 393 if (!IsOSSupported()) { 394 LOG(ERROR) << "Requires XP SP3 or later."; 395 return HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION); 396 } 397 398 result = InstallDriver(install_path); 399 if (FAILED(result)) { 400 LOG(ERROR) << "Unable to install driver."; 401 return result; 402 } 403 404 result = RegisterPortMonitor(true, install_path); 405 if (FAILED(result)) { 406 LOG(ERROR) << "Unable to register port monitor."; 407 return result; 408 } 409 410 result = InstallPrinter(); 411 if (FAILED(result) && 412 result != HRESULT_FROM_WIN32(ERROR_PRINTER_ALREADY_EXISTS)) { 413 LOG(ERROR) << "Unable to install printer."; 414 return result; 415 } 416 return S_OK; 417 } 418 419 HRESULT TryUnregisterVirtualDriver() { 420 HRESULT result = S_OK; 421 result = UninstallPrinter(); 422 if (FAILED(result)) { 423 LOG(ERROR) << "Unable to delete printer."; 424 return result; 425 } 426 result = UninstallDriver(); 427 if (FAILED(result)) { 428 LOG(ERROR) << "Unable to remove driver."; 429 return result; 430 } 431 // The second argument is ignored if the first is false. 432 result = RegisterPortMonitor(false, base::FilePath()); 433 if (FAILED(result)) { 434 LOG(ERROR) << "Unable to remove port monitor."; 435 return result; 436 } 437 return S_OK; 438 } 439 440 HRESULT UnregisterVirtualDriver() { 441 HRESULT hr = S_FALSE; 442 for (int i = 0; i < 2; ++i) { 443 hr = TryUnregisterVirtualDriver(); 444 if (SUCCEEDED(hr)) { 445 break; 446 } 447 // Restart spooler and try again. 448 SpoolerServiceCommand("stop"); 449 SpoolerServiceCommand("start"); 450 } 451 return hr; 452 } 453 454 HRESULT DoUninstall() { 455 DeleteGoogleUpdateKeys(kGoogleUpdateProductId); 456 HRESULT result = UnregisterVirtualDriver(); 457 if (FAILED(result)) 458 return result; 459 DeleteUninstallKey(kUninstallId); 460 DeleteProgramDir(kDelete); 461 return S_OK; 462 } 463 464 HRESULT DoUnregister() { 465 return UnregisterVirtualDriver(); 466 } 467 468 HRESULT DoRegister(const base::FilePath& install_path) { 469 HRESULT result = UnregisterVirtualDriver(); 470 if (FAILED(result)) 471 return result; 472 return RegisterVirtualDriver(install_path); 473 } 474 475 HRESULT DoDelete(const base::FilePath& install_path) { 476 if (install_path.value().empty()) 477 return E_INVALIDARG; 478 if (!base::DirectoryExists(install_path)) 479 return S_FALSE; 480 Sleep(5000); // Give parent some time to exit. 481 return base::DeleteFile(install_path, true) ? S_OK : E_FAIL; 482 } 483 484 HRESULT DoInstall(const base::FilePath& install_path) { 485 HRESULT result = UnregisterVirtualDriver(); 486 if (FAILED(result)) { 487 LOG(ERROR) << "Unable to unregister."; 488 return result; 489 } 490 base::FilePath old_install_path = GetInstallLocation(kUninstallId); 491 if (!old_install_path.value().empty() && 492 install_path != old_install_path) { 493 if (base::DirectoryExists(old_install_path)) 494 base::DeleteFile(old_install_path, true); 495 } 496 CreateUninstallKey(kUninstallId, LoadLocalString(IDS_DRIVER_NAME), 497 kUninstallSwitch); 498 result = RegisterVirtualDriver(install_path); 499 if (FAILED(result)) 500 return result; 501 SetGoogleUpdateKeys(kGoogleUpdateProductId, kNameValue); 502 return result; 503 } 504 505 HRESULT ExecuteCommands() { 506 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 507 508 base::FilePath exe_path; 509 if (FAILED(PathService::Get(base::DIR_EXE, &exe_path)) || 510 !base::DirectoryExists(exe_path)) { 511 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); 512 } 513 514 if (command_line.HasSwitch(kDelete)) { 515 return DoDelete(command_line.GetSwitchValuePath(kDelete)); 516 } else if (command_line.HasSwitch(kUninstallSwitch)) { 517 return DoUninstall(); 518 } else if (command_line.HasSwitch(kInstallSwitch)) { 519 return DoInstall(exe_path); 520 } else if (command_line.HasSwitch(kUnregisterSwitch)) { 521 return DoUnregister(); 522 } else if (command_line.HasSwitch(kRegisterSwitch)) { 523 return DoRegister(exe_path); 524 } 525 526 return E_INVALIDARG; 527 } 528 529 } // namespace 530 531 } // namespace cloud_print 532 533 int WINAPI WinMain(__in HINSTANCE hInstance, 534 __in HINSTANCE hPrevInstance, 535 __in LPSTR lpCmdLine, 536 __in int nCmdShow) { 537 using namespace cloud_print; 538 539 base::AtExitManager at_exit_manager; 540 CommandLine::Init(0, NULL); 541 542 HRESULT retval = ExecuteCommands(); 543 544 if (retval == HRESULT_FROM_WIN32(ERROR_BAD_DRIVER)) { 545 SetGoogleUpdateError(kGoogleUpdateProductId, 546 LoadLocalString(IDS_ERROR_NO_XPS)); 547 } else if (FAILED(retval)) { 548 SetGoogleUpdateError(kGoogleUpdateProductId, retval); 549 } 550 551 VLOG(0) << GetErrorMessage(retval) 552 << " HRESULT=0x" << std::setbase(16) << retval; 553 554 // Installer is silent by default as required by Google Update. 555 if (CommandLine::ForCurrentProcess()->HasSwitch("verbose")) { 556 DisplayWindowsMessage(NULL, retval, LoadLocalString(IDS_DRIVER_NAME)); 557 } 558 return retval; 559 } 560