summaryrefslogtreecommitdiffstats
path: root/cloud_print
diff options
context:
space:
mode:
Diffstat (limited to 'cloud_print')
-rw-r--r--cloud_print/virtual_driver/win/install/setup.cc186
-rw-r--r--cloud_print/virtual_driver/win/port_monitor/port_monitor.cc31
-rw-r--r--cloud_print/virtual_driver/win/virtual_driver_consts.cc8
-rw-r--r--cloud_print/virtual_driver/win/virtual_driver_consts.h3
-rw-r--r--cloud_print/virtual_driver/win/virtual_driver_helpers.cc24
-rw-r--r--cloud_print/virtual_driver/win/virtual_driver_helpers.h5
6 files changed, 219 insertions, 38 deletions
diff --git a/cloud_print/virtual_driver/win/install/setup.cc b/cloud_print/virtual_driver/win/install/setup.cc
index 84bd746..8724429 100644
--- a/cloud_print/virtual_driver/win/install/setup.cc
+++ b/cloud_print/virtual_driver/win/install/setup.cc
@@ -3,10 +3,12 @@
// found in the LICENSE file.
#include <windows.h>
+#include <winspool.h>
#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/file_util.h"
+#include "base/logging.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/win/scoped_handle.h"
@@ -23,6 +25,15 @@ bool IsSystem64Bit() {
(arch == base::win::OSInfo::IA64_ARCHITECTURE);
}
+HRESULT GetGpdPath(FilePath* path) {
+ if (!PathService::Get(base::DIR_EXE, path)) {
+ LOG(ERROR) << "Unable to get install path.";
+ return ERROR_PATH_NOT_FOUND;
+ }
+ *path = path->Append(L"gcp.gpd");
+ return S_OK;
+}
+
const wchar_t *GetPortMonitorDllName() {
if (IsSystem64Bit()) {
return cloud_print::kPortMonitorDllName64;
@@ -33,6 +44,7 @@ const wchar_t *GetPortMonitorDllName() {
HRESULT GetPortMonitorDllPath(FilePath* path) {
if (!PathService::Get(base::DIR_EXE, path)) {
+ LOG(ERROR) << "Unable to get install path.";
return ERROR_PATH_NOT_FOUND;
}
*path = path->Append(GetPortMonitorDllName());
@@ -49,6 +61,7 @@ HRESULT GetPortMonitorInstallPath(FilePath* path) {
*path = path->Append(L"sysnative");
} else {
if (!PathService::Get(base::DIR_SYSTEM, path)) {
+ LOG(ERROR) << "Unable to get system path.";
return ERROR_PATH_NOT_FOUND;
}
}
@@ -58,6 +71,7 @@ HRESULT GetPortMonitorInstallPath(FilePath* path) {
HRESULT GetRegsvr32Path(FilePath* path) {
if (!PathService::Get(base::DIR_SYSTEM, path)) {
+ LOG(ERROR) << "Unable to get system path.";
return ERROR_PATH_NOT_FOUND;
}
*path = path->Append(FilePath(L"regsvr32.exe"));
@@ -69,21 +83,26 @@ HRESULT RegisterPortMonitor(bool install) {
HRESULT result = S_OK;
result = GetPortMonitorInstallPath(&target_path);
if (!SUCCEEDED(result)) {
+ LOG(ERROR) << "Unable to get port monitor target path.";
return result;
}
- FilePath dll_path;
- result = GetPortMonitorDllPath(&dll_path);
+ FilePath source_path;
+ result = GetPortMonitorDllPath(&source_path);
if (!SUCCEEDED(result)) {
+ LOG(ERROR) << "Unable to get dll source path.";
return result;
}
if (install) {
- if (!file_util::CopyFileW(dll_path, target_path)) {
- return cloud_print::GetLastHResult();
+ if (!file_util::CopyFileW(source_path, target_path)) {
+ LOG(ERROR) << "Unable copy port monitor dll from " <<
+ source_path.value() << " to " << target_path.value();
+ return ERROR_ACCESS_DENIED;
}
}
FilePath regsvr32_path;
result = GetRegsvr32Path(&regsvr32_path);
if (!SUCCEEDED(result)) {
+ LOG(ERROR) << "Can't find regsvr32.exe.";
return result;
}
CommandLine command_line(regsvr32_path);
@@ -91,36 +110,181 @@ HRESULT RegisterPortMonitor(bool install) {
if (!install) {
command_line.AppendArg("/u");
}
- command_line.AppendArgPath(dll_path);
+ command_line.AppendArgPath(source_path);
HANDLE process_handle;
if (!base::LaunchApp(command_line.command_line_string(),
true,
false,
&process_handle)) {
- return cloud_print::GetLastHResult();
+ LOG(ERROR) << "Unable to launch regsvr32.exe.";
+ return ERROR_NOT_SUPPORTED;
}
base::win::ScopedHandle scoped_process_handle(process_handle);
DWORD exit_code = S_OK;
if (!GetExitCodeProcess(scoped_process_handle, &exit_code)) {
- return cloud_print::GetLastHResult();
+ HRESULT result = cloud_print::GetLastHResult();
+ LOG(ERROR) << "Unable to get regsvr32.exe exit code.";
+ return result;
}
if (exit_code != 0) {
- return HRESULT_FROM_WIN32(exit_code);
+ LOG(ERROR) << "Regsvr32.exe failed with " << exit_code;
+ return HRESULT_FROM_WIN32(exit_code);
}
if (!install) {
if (!file_util::Delete(target_path, false)) {
- return cloud_print::GetLastHResult();
+ LOG(ERROR) << "Unable to delete " << target_path.value();
+ return ERROR_ACCESS_DENIED;
}
}
return S_OK;
}
+HRESULT InstallGpd() {
+ HRESULT result = S_OK;
+ FilePath source_path;
+ result = GetGpdPath(&source_path);
+ if (!SUCCEEDED(result)) {
+ return result;
+ }
+ FilePath driver_dir;
+ cloud_print::GetPrinterDriverDir(&driver_dir);
+ FilePath xps_path = driver_dir.Append(L"mxdwdrv.dll");
+ FilePath ui_path = driver_dir.Append(L"unidrvui.dll");
+ FilePath ui_help_path = driver_dir.Append(L"unidrv.hlp");
+ DRIVER_INFO_6 driver_info = {0};
+ driver_info.cVersion = 3;
+ // None of the print API structures likes constant strings even though they
+ // don't modify the string. const_casting is the cleanest option.
+ driver_info.pName = const_cast<LPWSTR>(cloud_print::kVirtualDriverName);
+ driver_info.pDriverPath = const_cast<LPWSTR>(xps_path.value().c_str());
+ driver_info.pConfigFile = const_cast<LPWSTR>(ui_path.value().c_str());
+ driver_info.pDataFile = const_cast<LPWSTR>(source_path.value().c_str());
+ driver_info.pHelpFile = const_cast<LPWSTR>(ui_help_path.value().c_str());
+ // TODO(abodenha@chromium.org) Pull these strings from resources.
+ driver_info.pszMfgName = L"Google";
+ driver_info.pszProvider = driver_info.pszMfgName;
+ driver_info.pszOEMUrl = L"http://www.google.com/cloudprint";
+ driver_info.dwlDriverVersion = 1;
+ driver_info.pDefaultDataType = L"RAW";
+ // TODO(abodenha@chromium.org) Properly handle dependencies.
+ // GPD files are often dependent on various Windows core drivers.
+ // I haven't found a reliable way to express those dependencies
+ // other than using an INF for installation.
+ if (!AddPrinterDriverEx(NULL,
+ 6,
+ reinterpret_cast<BYTE*>(&driver_info),
+ APD_COPY_NEW_FILES|APD_COPY_FROM_DIRECTORY)) {
+ result = cloud_print::GetLastHResult();
+ LOG(ERROR) << "Unable to add printer driver";
+ return result;
+ }
+ return S_OK;
+}
+
+HRESULT UninstallGpd() {
+ int tries = 10;
+ while (!DeletePrinterDriverEx(NULL,
+ NULL,
+ const_cast<LPWSTR>
+ (cloud_print::kVirtualDriverName),
+ DPD_DELETE_UNUSED_FILES,
+ 0) && tries > 0) {
+ // After deleting the printer it can take a few seconds before
+ // the driver is free for deletion. Retry a few times before giving up.
+ LOG(WARNING) << "Attempt to delete printer driver failed. Retrying.";
+ tries--;
+ Sleep(2000);
+ }
+ if (tries <= 0) {
+ HRESULT result = cloud_print::GetLastHResult();
+ LOG(ERROR) << "Unable to delete printer driver.";
+ return result;
+ }
+ return S_OK;
+}
+
+HRESULT InstallPrinter(void) {
+ PRINTER_INFO_2 printer_info = {0};
+ printer_info.pPrinterName =
+ const_cast<LPWSTR>(cloud_print::kVirtualDriverName);
+ printer_info.pPortName = const_cast<LPWSTR>(cloud_print::kPortName);
+ printer_info.pDriverName =
+ const_cast<LPWSTR>(cloud_print::kVirtualDriverName);
+ printer_info.pPrinterName = printer_info.pDriverName;
+ // TODO(abodenha@chromium.org) pComment should be localized.
+ printer_info.pComment = const_cast<LPWSTR>(cloud_print::kVirtualDriverName);
+ printer_info.Attributes = PRINTER_ATTRIBUTE_DIRECT|PRINTER_ATTRIBUTE_LOCAL;
+ printer_info.pPrintProcessor = L"winprint";
+ printer_info.pDatatype = L"RAW";
+ HANDLE handle = AddPrinter(NULL, 2, reinterpret_cast<BYTE*>(&printer_info));
+ if (handle == NULL) {
+ HRESULT result = cloud_print::GetLastHResult();
+ LOG(ERROR) << "Unable to add printer";
+ return result;
+ }
+ ClosePrinter(handle);
+ return S_OK;
+}
+
+HRESULT UninstallPrinter(void) {
+ HANDLE handle = NULL;
+ PRINTER_DEFAULTS printer_defaults = {0};
+ printer_defaults.DesiredAccess = PRINTER_ALL_ACCESS;
+ if (!OpenPrinter(const_cast<LPWSTR>(cloud_print::kVirtualDriverName),
+ &handle,
+ &printer_defaults)) {
+ // If we can't open the printer, it was probably already removed.
+ LOG(WARNING) << "Unable to open printer";
+ return S_OK;
+ }
+ if (!DeletePrinter(handle)) {
+ HRESULT result = cloud_print::GetLastHResult();
+ LOG(ERROR) << "Unable to delete printer";
+ ClosePrinter(handle);
+ return result;
+ }
+ ClosePrinter(handle);
+ return S_OK;
+}
+
HRESULT InstallVirtualDriver(void) {
- return RegisterPortMonitor(true);
+ HRESULT result = S_OK;
+ result = RegisterPortMonitor(true);
+ if (!SUCCEEDED(result)) {
+ LOG(ERROR) << "Unable to register port monitor.";
+ return result;
+ }
+ result = InstallGpd();
+ if (!SUCCEEDED(result)) {
+ LOG(ERROR) << "Unable to install gpd.";
+ return result;
+ }
+ result = InstallPrinter();
+ if (!SUCCEEDED(result)) {
+ LOG(ERROR) << "Unable to install printer.";
+ return result;
+ }
+ return S_OK;
}
HRESULT UninstallVirtualDriver(void) {
- return RegisterPortMonitor(false);
+ HRESULT result = S_OK;
+ result = UninstallPrinter();
+ if (!SUCCEEDED(result)) {
+ LOG(ERROR) << "Unable to uninstall gpd.";
+ return result;
+ }
+ result = UninstallGpd();
+ if (!SUCCEEDED(result)) {
+ LOG(ERROR) << "Unable to remove gpd.";
+ return result;
+ }
+ result = RegisterPortMonitor(false);
+ if (!SUCCEEDED(result)) {
+ LOG(ERROR) << "Unable to remove port monitor.";
+ return result;
+ }
+ return S_OK;
}
} // namespace
diff --git a/cloud_print/virtual_driver/win/port_monitor/port_monitor.cc b/cloud_print/virtual_driver/win/port_monitor/port_monitor.cc
index ff43e1e..f7b3437 100644
--- a/cloud_print/virtual_driver/win/port_monitor/port_monitor.cc
+++ b/cloud_print/virtual_driver/win/port_monitor/port_monitor.cc
@@ -65,8 +65,6 @@ const wchar_t *kPortMonitorDllName = kPortMonitorDllName64;
const wchar_t *kPortMonitorDllName = kPortMonitorDllName32;
#endif
-const wchar_t kPortName[] = L"GCP:";
-
const wchar_t kXpsMimeType[] = L"application/vnd.ms-xpsdocument";
const size_t kMaxCommandLineLen = 0x7FFF;
@@ -117,29 +115,10 @@ MONITOR2 g_monitor_2 = {
Monitor2Shutdown
};
-// Gets the standard install path for "version 3" print drivers.
-HRESULT GetPrinterDriverPath(FilePath* path) {
- BYTE driver_dir_buffer[MAX_PATH * sizeof(wchar_t)];
- DWORD needed = 0;
- if (!GetPrinterDriverDirectory(NULL,
- NULL,
- 1,
- driver_dir_buffer,
- MAX_PATH * sizeof(wchar_t),
- &needed)) {
- // We could try to allocate a larger buffer if needed > MAX_PATH
- // but that really shouldn't happen.
- return cloud_print::GetLastHResult();
- }
- *path = FilePath(reinterpret_cast<wchar_t*>(driver_dir_buffer));
- *path = path->Append(L"3");
- return S_OK;
-}
-
// Returns true if Xps support is installed.
bool XpsIsInstalled() {
FilePath xps_path;
- if (!SUCCEEDED(GetPrinterDriverPath(&xps_path))) {
+ if (!SUCCEEDED(GetPrinterDriverDir(&xps_path))) {
return false;
}
xps_path = xps_path.Append(L"mxdwdrv.dll");
@@ -334,7 +313,7 @@ BOOL WINAPI Monitor2EnumPorts(HANDLE,
SetLastError(ERROR_INVALID_LEVEL);
return FALSE;
}
- *needed_bytes += sizeof(kPortName);
+ *needed_bytes += static_cast<DWORD>(kPortNameSize);
if (ports_size < *needed_bytes) {
LOG(WARNING) << *needed_bytes << " bytes are required. Only "
<< ports_size << " were allocated.";
@@ -358,15 +337,15 @@ BOOL WINAPI Monitor2EnumPorts(HANDLE,
// EnumPorts to fail until the spooler is restarted.
// This is NOT mentioned in the documentation.
wchar_t* string_target =
- reinterpret_cast<wchar_t*>(ports + ports_size - sizeof(kPortName));
+ reinterpret_cast<wchar_t*>(ports + ports_size - kPortNameSize);
if (level == 1) {
PORT_INFO_1* port_info = reinterpret_cast<PORT_INFO_1*>(ports);
port_info->pName = string_target;
- StringCbCopy(port_info->pName, sizeof(kPortName), kPortName);
+ StringCbCopy(port_info->pName, kPortNameSize, kPortName);
} else {
PORT_INFO_2* port_info = reinterpret_cast<PORT_INFO_2*>(ports);
port_info->pPortName = string_target;
- StringCbCopy(port_info->pPortName, sizeof(kPortName), kPortName);
+ StringCbCopy(port_info->pPortName, kPortNameSize, kPortName);
port_info->pMonitorName = NULL;
port_info->pDescription = NULL;
port_info->fPortType = PORT_TYPE_WRITE;
diff --git a/cloud_print/virtual_driver/win/virtual_driver_consts.cc b/cloud_print/virtual_driver/win/virtual_driver_consts.cc
index 78117f8..d8b02ea 100644
--- a/cloud_print/virtual_driver/win/virtual_driver_consts.cc
+++ b/cloud_print/virtual_driver/win/virtual_driver_consts.cc
@@ -9,5 +9,13 @@
namespace cloud_print {
const wchar_t kPortMonitorDllName64[] = L"gcp_portmon64.dll";
const wchar_t kPortMonitorDllName32[] = L"gcp_portmon.dll";
+const wchar_t kPortName[] = L"GCP:";
+const size_t kPortNameSize = sizeof(kPortName);
+
+// The driver name is user visible so it SHOULD be localized, BUT
+// the name is used as a key to find both the driver and printer.
+// We'll need to be careful. If the name changes for the
+// driver it could create bugs.
+const wchar_t kVirtualDriverName[] = L"Google Cloud Print Virtual Printer";
}
diff --git a/cloud_print/virtual_driver/win/virtual_driver_consts.h b/cloud_print/virtual_driver/win/virtual_driver_consts.h
index 6d92ea8..acf0b47 100644
--- a/cloud_print/virtual_driver/win/virtual_driver_consts.h
+++ b/cloud_print/virtual_driver/win/virtual_driver_consts.h
@@ -9,6 +9,9 @@
namespace cloud_print {
extern const wchar_t kPortMonitorDllName64[];
extern const wchar_t kPortMonitorDllName32[];
+extern const wchar_t kPortName[];
+extern const size_t kPortNameSize;
+extern const wchar_t kVirtualDriverName[];
}
#endif // CLOUD_PRINT_VIRTUAL_DRIVER_WIN_VIRTUAL_DRIVER_CONSTS_H_
diff --git a/cloud_print/virtual_driver/win/virtual_driver_helpers.cc b/cloud_print/virtual_driver/win/virtual_driver_helpers.cc
index c59211c..19d5574 100644
--- a/cloud_print/virtual_driver/win/virtual_driver_helpers.cc
+++ b/cloud_print/virtual_driver/win/virtual_driver_helpers.cc
@@ -4,6 +4,8 @@
#include "cloud_print/virtual_driver/win/virtual_driver_helpers.h"
#include <windows.h>
+#include <winspool.h>
+#include "base/file_util.h"
#include "cloud_print/virtual_driver/win/virtual_driver_consts.h"
namespace cloud_print {
@@ -20,12 +22,32 @@ void DisplayWindowsMessage(HWND hwnd, HRESULT message_id) {
message_text,
kMaxMessageLen,
NULL);
- ::MessageBox(hwnd, message_text, L"GCP", MB_OK);
+ ::MessageBox(hwnd, message_text, kVirtualDriverName, MB_OK);
}
HRESULT GetLastHResult() {
DWORD error_code = GetLastError();
return HRESULT_FROM_WIN32(error_code);
}
+
+HRESULT GetPrinterDriverDir(FilePath* path) {
+ BYTE driver_dir_buffer[MAX_PATH * sizeof(wchar_t)];
+ DWORD needed = 0;
+ if (!GetPrinterDriverDirectory(NULL,
+ NULL,
+ 1,
+ driver_dir_buffer,
+ MAX_PATH * sizeof(wchar_t),
+ &needed)) {
+ // We could try to allocate a larger buffer if needed > MAX_PATH
+ // but that really shouldn't happen.
+ return cloud_print::GetLastHResult();
+ }
+ *path = FilePath(reinterpret_cast<wchar_t*>(driver_dir_buffer));
+
+ // The XPS driver is a "Level 3" driver
+ *path = path->Append(L"3");
+ return S_OK;
+}
}
diff --git a/cloud_print/virtual_driver/win/virtual_driver_helpers.h b/cloud_print/virtual_driver/win/virtual_driver_helpers.h
index d8cc089..6d2a753 100644
--- a/cloud_print/virtual_driver/win/virtual_driver_helpers.h
+++ b/cloud_print/virtual_driver/win/virtual_driver_helpers.h
@@ -8,6 +8,8 @@
#include <windows.h>
+class FilePath;
+
namespace cloud_print {
// Convert an HRESULT to a localized string and display it in a message box.
@@ -15,6 +17,9 @@ void DisplayWindowsMessage(HWND hwnd, HRESULT message_id);
// Similar to the Windows API call GetLastError but returns an HRESULT.
HRESULT GetLastHResult();
+
+// Gets the standard install path for "version 3" print drivers.
+HRESULT GetPrinterDriverDir(FilePath* path);
}
#endif // CLOUD_PRINT_VIRTUAL_DRIVER_WIN_HELPERS_H_