Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <windows.h> | 5 #include <windows.h> |
| 6 #include <winspool.h> | 6 #include <winspool.h> |
| 7 | 7 |
| 8 #include "base/at_exit.h" | 8 #include "base/at_exit.h" |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
| 11 #include "base/file_version_info_win.h" | |
| 11 #include "base/logging.h" | 12 #include "base/logging.h" |
| 12 #include "base/path_service.h" | 13 #include "base/path_service.h" |
| 13 #include "base/process_util.h" | 14 #include "base/process_util.h" |
| 14 #include "base/win/scoped_handle.h" | 15 #include "base/win/scoped_handle.h" |
| 15 #include "base/win/windows_version.h" | 16 #include "cloud_print/virtual_driver/win/virtual_driver_common_resources.h" |
| 16 #include "cloud_print/virtual_driver/win/virtual_driver_consts.h" | |
| 17 #include "cloud_print/virtual_driver/win/virtual_driver_helpers.h" | 17 #include "cloud_print/virtual_driver/win/virtual_driver_helpers.h" |
| 18 #include "grit/virtual_driver_setup_resources.h" | |
| 18 | 19 |
| 19 namespace { | 20 namespace { |
| 20 | 21 |
| 21 bool IsSystem64Bit() { | |
| 22 base::win::OSInfo::WindowsArchitecture arch = | |
| 23 base::win::OSInfo::GetInstance()->architecture(); | |
| 24 return (arch == base::win::OSInfo::X64_ARCHITECTURE) || | |
| 25 (arch == base::win::OSInfo::IA64_ARCHITECTURE); | |
| 26 } | |
| 27 | |
| 28 HRESULT GetGpdPath(FilePath* path) { | 22 HRESULT GetGpdPath(FilePath* path) { |
| 29 if (!PathService::Get(base::DIR_EXE, path)) { | 23 if (!PathService::Get(base::DIR_EXE, path)) { |
| 30 LOG(ERROR) << "Unable to get install path."; | 24 LOG(ERROR) << "Unable to get install path."; |
| 31 return ERROR_PATH_NOT_FOUND; | 25 return ERROR_PATH_NOT_FOUND; |
| 32 } | 26 } |
| 33 *path = path->Append(L"gcp.gpd"); | 27 wchar_t driver_name[MAX_PATH]; |
| 28 cloud_print::LoadLocalString(IDS_GCP_DRIVER, | |
| 29 driver_name, | |
| 30 MAX_PATH); | |
| 31 *path = path->Append(driver_name); | |
| 34 return S_OK; | 32 return S_OK; |
| 35 } | 33 } |
| 36 | 34 |
| 37 const wchar_t *GetPortMonitorDllName() { | |
| 38 if (IsSystem64Bit()) { | |
| 39 return cloud_print::kPortMonitorDllName64; | |
| 40 } else { | |
| 41 return cloud_print::kPortMonitorDllName32; | |
| 42 } | |
| 43 } | |
| 44 | |
| 45 HRESULT GetPortMonitorDllPath(FilePath* path) { | 35 HRESULT GetPortMonitorDllPath(FilePath* path) { |
| 46 if (!PathService::Get(base::DIR_EXE, path)) { | 36 if (!PathService::Get(base::DIR_EXE, path)) { |
| 47 LOG(ERROR) << "Unable to get install path."; | 37 LOG(ERROR) << "Unable to get install path."; |
| 48 return ERROR_PATH_NOT_FOUND; | 38 return ERROR_PATH_NOT_FOUND; |
| 49 } | 39 } |
| 50 *path = path->Append(GetPortMonitorDllName()); | 40 FilePath dll_name; |
| 41 cloud_print::GetPortMonitorDllName(&dll_name); | |
| 42 *path = path->Append(dll_name); | |
| 51 return S_OK; | 43 return S_OK; |
| 52 } | 44 } |
| 53 | 45 |
| 54 HRESULT GetPortMonitorInstallPath(FilePath* path) { | 46 HRESULT GetPortMonitorInstallPath(FilePath* path) { |
| 55 if (IsSystem64Bit()) { | 47 if (cloud_print::IsSystem64Bit()) { |
| 56 if (!PathService::Get(base::DIR_WINDOWS, path)) { | 48 if (!PathService::Get(base::DIR_WINDOWS, path)) { |
| 57 return ERROR_PATH_NOT_FOUND; | 49 return ERROR_PATH_NOT_FOUND; |
| 58 } | 50 } |
| 59 // Sysnative will bypass filesystem redirection and give us | 51 // Sysnative will bypass filesystem redirection and give us |
| 60 // the location of the 64bit system32 from a 32 bit process. | 52 // the location of the 64bit system32 from a 32 bit process. |
| 61 *path = path->Append(L"sysnative"); | 53 *path = path->Append(L"sysnative"); |
| 62 } else { | 54 } else { |
| 63 if (!PathService::Get(base::DIR_SYSTEM, path)) { | 55 if (!PathService::Get(base::DIR_SYSTEM, path)) { |
| 64 LOG(ERROR) << "Unable to get system path."; | 56 LOG(ERROR) << "Unable to get system path."; |
| 65 return ERROR_PATH_NOT_FOUND; | 57 return ERROR_PATH_NOT_FOUND; |
| 66 } | 58 } |
| 67 } | 59 } |
| 68 *path = path->Append(GetPortMonitorDllName()); | 60 FilePath dll_name; |
| 61 cloud_print::GetPortMonitorDllName(&dll_name); | |
| 62 *path = path->Append(dll_name); | |
| 69 return S_OK; | 63 return S_OK; |
| 70 } | 64 } |
| 71 | 65 |
| 72 HRESULT GetRegsvr32Path(FilePath* path) { | 66 HRESULT GetRegsvr32Path(FilePath* path) { |
| 73 if (!PathService::Get(base::DIR_SYSTEM, path)) { | 67 if (!PathService::Get(base::DIR_SYSTEM, path)) { |
| 74 LOG(ERROR) << "Unable to get system path."; | 68 LOG(ERROR) << "Unable to get system path."; |
| 75 return ERROR_PATH_NOT_FOUND; | 69 return ERROR_PATH_NOT_FOUND; |
| 76 } | 70 } |
| 77 *path = path->Append(FilePath(L"regsvr32.exe")); | 71 *path = path->Append(FilePath(L"regsvr32.exe")); |
| 78 return S_OK; | 72 return S_OK; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 132 } | 126 } |
| 133 if (!install) { | 127 if (!install) { |
| 134 if (!file_util::Delete(target_path, false)) { | 128 if (!file_util::Delete(target_path, false)) { |
| 135 LOG(ERROR) << "Unable to delete " << target_path.value(); | 129 LOG(ERROR) << "Unable to delete " << target_path.value(); |
| 136 return ERROR_ACCESS_DENIED; | 130 return ERROR_ACCESS_DENIED; |
| 137 } | 131 } |
| 138 } | 132 } |
| 139 return S_OK; | 133 return S_OK; |
| 140 } | 134 } |
| 141 | 135 |
| 136 DWORDLONG GetVersionNumber() { | |
| 137 DWORDLONG retval = 0; | |
| 138 scoped_ptr<FileVersionInfo> version_info( | |
| 139 FileVersionInfo::CreateFileVersionInfoForCurrentModule()); | |
| 140 if (version_info.get()) { | |
| 141 FileVersionInfoWin* version_info_win = | |
| 142 static_cast<FileVersionInfoWin*>(version_info.get()); | |
| 143 VS_FIXEDFILEINFO* fixed_file_info = version_info_win->fixed_file_info(); | |
| 144 retval = fixed_file_info->dwFileVersionMS; | |
| 145 retval <<= 32; | |
| 146 retval |= fixed_file_info->dwFileVersionMS; | |
| 147 } | |
| 148 return retval; | |
| 149 } | |
| 150 | |
| 142 HRESULT InstallGpd() { | 151 HRESULT InstallGpd() { |
| 152 DRIVER_INFO_6 driver_info = {0}; | |
| 143 HRESULT result = S_OK; | 153 HRESULT result = S_OK; |
| 154 | |
| 155 // Set up paths for the files we depend on. | |
| 144 FilePath source_path; | 156 FilePath source_path; |
| 157 FilePath driver_dir; | |
| 158 cloud_print::GetPrinterDriverDir(&driver_dir); | |
| 159 wchar_t buffer[MAX_PATH]; | |
| 160 cloud_print::LoadLocalString(IDS_XPS_DRIVER, buffer, MAX_PATH); | |
|
sanjeevr
2011/05/09 19:39:11
Do the DLL names need to be in the resource?
| |
| 161 FilePath xps_path = driver_dir.Append(buffer); | |
| 162 cloud_print::LoadLocalString(IDS_UI_DRIVER, buffer, MAX_PATH); | |
| 163 FilePath ui_path = driver_dir.Append(buffer); | |
| 164 cloud_print::LoadLocalString(IDS_UI_HELP, buffer, MAX_PATH); | |
| 165 FilePath ui_help_path = driver_dir.Append(buffer); | |
| 145 result = GetGpdPath(&source_path); | 166 result = GetGpdPath(&source_path); |
| 146 if (!SUCCEEDED(result)) { | 167 if (!SUCCEEDED(result)) { |
| 147 return result; | 168 return result; |
| 148 } | 169 } |
| 149 FilePath driver_dir; | |
| 150 cloud_print::GetPrinterDriverDir(&driver_dir); | |
| 151 FilePath xps_path = driver_dir.Append(L"mxdwdrv.dll"); | |
| 152 FilePath ui_path = driver_dir.Append(L"unidrvui.dll"); | |
| 153 FilePath ui_help_path = driver_dir.Append(L"unidrv.hlp"); | |
| 154 DRIVER_INFO_6 driver_info = {0}; | |
| 155 driver_info.cVersion = 3; | |
| 156 // None of the print API structures likes constant strings even though they | 170 // None of the print API structures likes constant strings even though they |
| 157 // don't modify the string. const_casting is the cleanest option. | 171 // don't modify the string. const_casting is the cleanest option. |
| 158 driver_info.pName = const_cast<LPWSTR>(cloud_print::kVirtualDriverName); | 172 driver_info.pDataFile = const_cast<LPWSTR>(source_path.value().c_str()); |
| 173 driver_info.pHelpFile = const_cast<LPWSTR>(ui_help_path.value().c_str()); | |
| 159 driver_info.pDriverPath = const_cast<LPWSTR>(xps_path.value().c_str()); | 174 driver_info.pDriverPath = const_cast<LPWSTR>(xps_path.value().c_str()); |
| 160 driver_info.pConfigFile = const_cast<LPWSTR>(ui_path.value().c_str()); | 175 driver_info.pConfigFile = const_cast<LPWSTR>(ui_path.value().c_str()); |
| 161 driver_info.pDataFile = const_cast<LPWSTR>(source_path.value().c_str()); | 176 |
| 162 driver_info.pHelpFile = const_cast<LPWSTR>(ui_help_path.value().c_str()); | 177 // Set up user visible strings. |
| 163 // TODO(abodenha@chromium.org) Pull these strings from resources. | 178 wchar_t manufacturer[MAX_PATH]; |
| 164 driver_info.pszMfgName = L"Google"; | 179 cloud_print::LoadLocalString(IDS_GOOGLE, manufacturer, MAX_PATH); |
| 165 driver_info.pszProvider = driver_info.pszMfgName; | 180 driver_info.pszMfgName = manufacturer; |
| 166 driver_info.pszOEMUrl = L"http://www.google.com/cloudprint"; | 181 driver_info.pszProvider = manufacturer; |
| 167 driver_info.dwlDriverVersion = 1; | 182 wchar_t oem_url[MAX_PATH]; |
| 168 driver_info.pDefaultDataType = L"RAW"; | 183 cloud_print::LoadLocalString(IDS_GCP_URL, oem_url, MAX_PATH); |
| 184 driver_info.pszOEMUrl = oem_url; | |
| 185 driver_info.dwlDriverVersion = GetVersionNumber(); | |
| 186 wchar_t driver_name[MAX_PATH]; | |
| 187 cloud_print::LoadLocalString(IDS_DRIVER_NAME, | |
| 188 driver_name, | |
| 189 MAX_PATH); | |
| 190 driver_info.pName = driver_name; | |
| 191 | |
| 192 // Set up supported data type and print system version. | |
| 193 wchar_t data_type[MAX_PATH]; | |
| 194 cloud_print::LoadLocalString(IDS_DATA_TYPE, data_type, MAX_PATH); | |
| 195 driver_info.pDefaultDataType = data_type; | |
| 196 driver_info.cVersion = 3; | |
| 197 | |
| 169 // TODO(abodenha@chromium.org) Properly handle dependencies. | 198 // TODO(abodenha@chromium.org) Properly handle dependencies. |
| 170 // GPD files are often dependent on various Windows core drivers. | 199 // GPD files are often dependent on various Windows core drivers. |
| 171 // I haven't found a reliable way to express those dependencies | 200 // I haven't found a reliable way to express those dependencies |
| 172 // other than using an INF for installation. | 201 // other than using an INF for installation. |
| 173 if (!AddPrinterDriverEx(NULL, | 202 if (!AddPrinterDriverEx(NULL, |
| 174 6, | 203 6, |
| 175 reinterpret_cast<BYTE*>(&driver_info), | 204 reinterpret_cast<BYTE*>(&driver_info), |
| 176 APD_COPY_NEW_FILES|APD_COPY_FROM_DIRECTORY)) { | 205 APD_COPY_NEW_FILES|APD_COPY_FROM_DIRECTORY)) { |
| 177 result = cloud_print::GetLastHResult(); | 206 result = cloud_print::GetLastHResult(); |
| 178 LOG(ERROR) << "Unable to add printer driver"; | 207 LOG(ERROR) << "Unable to add printer driver"; |
| 179 return result; | 208 return result; |
| 180 } | 209 } |
| 181 return S_OK; | 210 return S_OK; |
| 182 } | 211 } |
| 183 | 212 |
| 184 HRESULT UninstallGpd() { | 213 HRESULT UninstallGpd() { |
| 185 int tries = 10; | 214 int tries = 10; |
| 215 wchar_t driver_name[MAX_PATH]; | |
| 216 cloud_print::LoadLocalString(IDS_DRIVER_NAME, driver_name, MAX_PATH); | |
| 186 while (!DeletePrinterDriverEx(NULL, | 217 while (!DeletePrinterDriverEx(NULL, |
| 187 NULL, | 218 NULL, |
| 188 const_cast<LPWSTR> | 219 driver_name, |
| 189 (cloud_print::kVirtualDriverName), | |
| 190 DPD_DELETE_UNUSED_FILES, | 220 DPD_DELETE_UNUSED_FILES, |
| 191 0) && tries > 0) { | 221 0) && tries > 0) { |
| 222 if (GetLastError() == ERROR_UNKNOWN_PRINTER_DRIVER) { | |
| 223 LOG(WARNING) << "Print driver is already uninstalled."; | |
| 224 return S_OK; | |
| 225 } | |
| 192 // After deleting the printer it can take a few seconds before | 226 // After deleting the printer it can take a few seconds before |
| 193 // the driver is free for deletion. Retry a few times before giving up. | 227 // the driver is free for deletion. Retry a few times before giving up. |
| 194 LOG(WARNING) << "Attempt to delete printer driver failed. Retrying."; | 228 LOG(WARNING) << "Attempt to delete printer driver failed. Retrying."; |
| 195 tries--; | 229 tries--; |
| 196 Sleep(2000); | 230 Sleep(2000); |
| 197 } | 231 } |
| 198 if (tries <= 0) { | 232 if (tries <= 0) { |
| 199 HRESULT result = cloud_print::GetLastHResult(); | 233 HRESULT result = S_OK; |
| 200 LOG(ERROR) << "Unable to delete printer driver."; | 234 LOG(ERROR) << "Unable to delete printer driver."; |
| 201 return result; | 235 return result; |
| 202 } | 236 } |
| 203 return S_OK; | 237 return S_OK; |
| 204 } | 238 } |
| 205 | 239 |
| 206 HRESULT InstallPrinter(void) { | 240 HRESULT InstallPrinter(void) { |
| 207 PRINTER_INFO_2 printer_info = {0}; | 241 PRINTER_INFO_2 printer_info = {0}; |
| 208 printer_info.pPrinterName = | 242 wchar_t driver_name[MAX_PATH]; |
| 209 const_cast<LPWSTR>(cloud_print::kVirtualDriverName); | 243 cloud_print::LoadLocalString(IDS_DRIVER_NAME, driver_name, MAX_PATH); |
| 210 printer_info.pPortName = const_cast<LPWSTR>(cloud_print::kPortName); | 244 printer_info.pDriverName = driver_name; |
| 211 printer_info.pDriverName = | 245 printer_info.pPrinterName = driver_name; |
| 212 const_cast<LPWSTR>(cloud_print::kVirtualDriverName); | 246 printer_info.pComment = driver_name; |
| 213 printer_info.pPrinterName = printer_info.pDriverName; | 247 wchar_t port_name[MAX_PATH]; |
| 214 // TODO(abodenha@chromium.org) pComment should be localized. | 248 cloud_print::LoadLocalString(IDS_PORT_NAME, port_name, MAX_PATH); |
| 215 printer_info.pComment = const_cast<LPWSTR>(cloud_print::kVirtualDriverName); | 249 printer_info.pPortName = port_name; |
| 216 printer_info.Attributes = PRINTER_ATTRIBUTE_DIRECT|PRINTER_ATTRIBUTE_LOCAL; | 250 printer_info.Attributes = PRINTER_ATTRIBUTE_DIRECT|PRINTER_ATTRIBUTE_LOCAL; |
| 217 printer_info.pPrintProcessor = L"winprint"; | 251 wchar_t print_processor[MAX_PATH]; |
| 218 printer_info.pDatatype = L"RAW"; | 252 cloud_print::LoadLocalString(IDS_PRINT_PROCESSOR, print_processor, MAX_PATH); |
| 253 printer_info.pPrintProcessor = print_processor; | |
| 254 wchar_t data_type[MAX_PATH]; | |
| 255 cloud_print::LoadLocalString(IDS_DATA_TYPE, data_type, MAX_PATH); | |
| 256 printer_info.pDatatype = data_type; | |
| 219 HANDLE handle = AddPrinter(NULL, 2, reinterpret_cast<BYTE*>(&printer_info)); | 257 HANDLE handle = AddPrinter(NULL, 2, reinterpret_cast<BYTE*>(&printer_info)); |
| 220 if (handle == NULL) { | 258 if (handle == NULL) { |
| 221 HRESULT result = cloud_print::GetLastHResult(); | 259 HRESULT result = cloud_print::GetLastHResult(); |
| 222 LOG(ERROR) << "Unable to add printer"; | 260 LOG(ERROR) << "Unable to add printer"; |
| 223 return result; | 261 return result; |
| 224 } | 262 } |
| 225 ClosePrinter(handle); | 263 ClosePrinter(handle); |
| 226 return S_OK; | 264 return S_OK; |
| 227 } | 265 } |
| 228 | 266 |
| 229 HRESULT UninstallPrinter(void) { | 267 HRESULT UninstallPrinter(void) { |
| 230 HANDLE handle = NULL; | 268 HANDLE handle = NULL; |
| 231 PRINTER_DEFAULTS printer_defaults = {0}; | 269 PRINTER_DEFAULTS printer_defaults = {0}; |
| 232 printer_defaults.DesiredAccess = PRINTER_ALL_ACCESS; | 270 printer_defaults.DesiredAccess = PRINTER_ALL_ACCESS; |
| 233 if (!OpenPrinter(const_cast<LPWSTR>(cloud_print::kVirtualDriverName), | 271 wchar_t driver_name[MAX_PATH]; |
| 234 &handle, | 272 cloud_print::LoadLocalString(IDS_DRIVER_NAME, driver_name, MAX_PATH); |
| 235 &printer_defaults)) { | 273 if (!OpenPrinter(driver_name, &handle, &printer_defaults)) { |
| 236 // If we can't open the printer, it was probably already removed. | 274 // If we can't open the printer, it was probably already removed. |
| 237 LOG(WARNING) << "Unable to open printer"; | 275 LOG(WARNING) << "Unable to open printer"; |
| 238 return S_OK; | 276 return S_OK; |
| 239 } | 277 } |
| 240 if (!DeletePrinter(handle)) { | 278 if (!DeletePrinter(handle)) { |
| 241 HRESULT result = cloud_print::GetLastHResult(); | 279 HRESULT result = cloud_print::GetLastHResult(); |
| 242 LOG(ERROR) << "Unable to delete printer"; | 280 LOG(ERROR) << "Unable to delete printer"; |
| 243 ClosePrinter(handle); | 281 ClosePrinter(handle); |
| 244 return result; | 282 return result; |
| 245 } | 283 } |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 295 __in int nCmdShow) { | 333 __in int nCmdShow) { |
| 296 base::AtExitManager at_exit_manager; | 334 base::AtExitManager at_exit_manager; |
| 297 CommandLine::Init(0, NULL); | 335 CommandLine::Init(0, NULL); |
| 298 HRESULT retval = S_OK; | 336 HRESULT retval = S_OK; |
| 299 if (CommandLine::ForCurrentProcess()->HasSwitch("uninstall")) { | 337 if (CommandLine::ForCurrentProcess()->HasSwitch("uninstall")) { |
| 300 retval = UninstallVirtualDriver(); | 338 retval = UninstallVirtualDriver(); |
| 301 } else { | 339 } else { |
| 302 retval = InstallVirtualDriver(); | 340 retval = InstallVirtualDriver(); |
| 303 } | 341 } |
| 304 if (!CommandLine::ForCurrentProcess()->HasSwitch("silent")) { | 342 if (!CommandLine::ForCurrentProcess()->HasSwitch("silent")) { |
| 305 cloud_print::DisplayWindowsMessage(NULL, retval); | 343 wchar_t driver_name[MAX_PATH]; |
| 344 cloud_print::LoadLocalString(IDS_DRIVER_NAME, driver_name, MAX_PATH); | |
| 345 cloud_print::DisplayWindowsMessage(NULL, retval, driver_name); | |
| 306 } | 346 } |
| 307 return retval; | 347 return retval; |
| 308 } | 348 } |
| 309 | 349 |
| OLD | NEW |