Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / cloud_print / virtual_driver / win / install / setup.cc
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 <iomanip>
6 #include <windows.h>
7 #include <winspool.h>
8 #include <setupapi.h>  // Must be included after windows.h
9
10 #include "base/at_exit.h"
11 #include "base/command_line.h"
12 #include "base/file_util.h"
13 #include "base/file_version_info_win.h"
14 #include "base/files/scoped_temp_dir.h"
15 #include "base/logging.h"
16 #include "base/path_service.h"
17 #include "base/process/process.h"
18 #include "base/process/launch.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                            &regsvr32_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, &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 = 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 }