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