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