15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "cloud_print/virtual_driver/win/port_monitor/port_monitor.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <windows.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <lmcons.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shellapi.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shlobj.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <strsafe.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <userenv.h>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <winspool.h>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/at_exit.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/files/file_enumerator.h"
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h"
21bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/process/launch.h"
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/process/process.h"
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string16.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/registry.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_handle.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/windows_version.h"
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/chrome_switches.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/launcher_support/chrome_launcher_support.h"
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "cloud_print/common/win/cloud_print_utils.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "cloud_print/virtual_driver/win/port_monitor/spooler_win.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "cloud_print/virtual_driver/win/virtual_driver_consts.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "cloud_print/virtual_driver/win/virtual_driver_helpers.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace cloud_print {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kIePath[] = L"Internet Explorer\\iexplore.exe";
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kChromeInstallUrl[] =
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "http://google.com/cloudprint/learn/chrome.html";
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kCloudPrintRegKey[] = L"Software\\Google\\CloudPrint";
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kXpsMimeType[] = L"application/vnd.ms-xpsdocument";
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const wchar_t kAppDataDir[] = L"Google\\Cloud Printer";
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct MonitorData {
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::AtExitManager> at_exit_manager;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct PortData {
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PortData() : job_id(0), printer_handle(NULL), file(0) {
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ~PortData() {
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Close();
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void Close() {
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (printer_handle) {
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ClosePrinter(printer_handle);
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      printer_handle = NULL;
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (file) {
65a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base::CloseFile(file);
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      file = NULL;
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD job_id;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HANDLE printer_handle;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FILE* file;
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath file_path;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ACCESS_MASK granted_access;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} XcvUiData;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MONITORUI g_monitor_ui = {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sizeof(MONITORUI),
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MonitorUiAddPortUi,
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MonitorUiConfigureOrDeletePortUI,
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MonitorUiConfigureOrDeletePortUI
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MONITOR2 g_monitor_2 = {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sizeof(MONITOR2),
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Monitor2EnumPorts,
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Monitor2OpenPort,
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NULL,           // OpenPortEx is not supported.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Monitor2StartDocPort,
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Monitor2WritePort,
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Monitor2ReadPort,
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Monitor2EndDocPort,
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Monitor2ClosePort,
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NULL,           // AddPort is not supported.
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NULL,           // AddPortEx is not supported.
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NULL,           // ConfigurePort is not supported.
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NULL,           // DeletePort is not supported.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NULL,
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NULL,           // SetPortTimeOuts is not supported.
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Monitor2XcvOpenPort,
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Monitor2XcvDataPort,
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Monitor2XcvClosePort,
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Monitor2Shutdown
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath GetAppDataDir() {
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath file_path;
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::Version version = base::win::GetVersion();
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int path_id = (version >= base::win::VERSION_VISTA) ?
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                base::DIR_LOCAL_APP_DATA_LOW : base::DIR_LOCAL_APP_DATA;
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!PathService::Get(path_id, &file_path)) {
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Can't get DIR_LOCAL_APP_DATA";
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return base::FilePath();
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return file_path.Append(kAppDataDir);
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Delete files which where not deleted by chrome.
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DeleteLeakedFiles(const base::FilePath& dir) {
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::Time delete_before = base::Time::Now() - base::TimeDelta::FromDays(1);
124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::FileEnumerator enumerator(dir, false, base::FileEnumerator::FILES);
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (base::FilePath file_path = enumerator.Next(); !file_path.empty();
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       file_path = enumerator.Next()) {
127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (enumerator.GetInfo().GetLastModifiedTime() < delete_before)
1287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::DeleteFile(file_path, false);
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Attempts to retrieve the title of the specified print job.
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On success returns TRUE and the first title_chars characters of the job title
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// are copied into title.
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On failure returns FALSE and title is unmodified.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetJobTitle(HANDLE printer_handle,
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 DWORD job_id,
138a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                 base::string16 *title) {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(printer_handle != NULL);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(title != NULL);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD bytes_needed = 0;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetJob(printer_handle, job_id, 1, NULL, 0, &bytes_needed);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bytes_needed == 0) {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Unable to get bytes needed for job info.";
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<BYTE[]> buffer(new BYTE[bytes_needed]);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetJob(printer_handle,
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              job_id,
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              1,
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              buffer.get(),
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              bytes_needed,
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              &bytes_needed)) {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Unable to get job info.";
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  JOB_INFO_1* job_info = reinterpret_cast<JOB_INFO_1*>(buffer.get());
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *title = job_info->pDocument;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Handler for the UI functions exported by the port monitor.
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Verifies that a valid parent Window exists and then just displays an
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// error message to let the user know that there is no interactive
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// configuration.
166a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void HandlePortUi(HWND hwnd, const base::string16& caption) {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (hwnd != NULL && IsWindow(hwnd)) {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DisplayWindowsMessage(hwnd, CO_E_NOT_SUPPORTED, cloud_print::kPortName);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Gets the primary token for the user that submitted the print job.
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetUserToken(HANDLE* primary_token) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HANDLE token = NULL;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!OpenThreadToken(GetCurrentThread(),
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      TOKEN_QUERY|TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY,
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      FALSE,
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      &token)) {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Unable to get thread token.";
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedHandle token_scoped(token);
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!DuplicateTokenEx(token,
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        TOKEN_QUERY|TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY,
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        NULL,
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        SecurityImpersonation,
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        TokenPrimary,
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        primary_token)) {
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Unable to get primary thread token.";
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Launches the Cloud Print dialog in Chrome.
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// xps_path references a file to print.
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// job_title is the title to be used for the resulting print job.
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool LaunchPrintDialog(const base::FilePath& xps_path,
199a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                       const base::string16& job_title) {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HANDLE token = NULL;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetUserToken(&token)) {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Unable to get user token.";
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedHandle primary_token_scoped(token);
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath chrome_path = GetChromeExePath();
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (chrome_path.empty()) {
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Unable to get chrome exe path.";
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandLine command_line(chrome_path);
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath chrome_profile = GetChromeProfilePath();
216a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!chrome_profile.empty())
217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    command_line.AppendSwitchPath(switches::kUserDataDir, chrome_profile);
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
219a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  command_line.AppendSwitchPath(switches::kCloudPrintFile, xps_path);
220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  command_line.AppendSwitchNative(switches::kCloudPrintFileType, kXpsMimeType);
221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  command_line.AppendSwitchNative(switches::kCloudPrintJobTitle, job_title);
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::LaunchOptions options;
2231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  options.as_user = primary_token_scoped.Get();
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::LaunchProcess(command_line, options, NULL);
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Launches a page to allow the user to download chrome.
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(abodenha@chromium.org) Point to a custom page explaining what's wrong
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// rather than the generic chrome download page.  See
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://code.google.com/p/chromium/issues/detail?id=112019
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LaunchChromeDownloadPage() {
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kIsUnittest)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HANDLE token = NULL;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetUserToken(&token)) {
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Unable to get user token.";
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedHandle token_scoped(token);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath ie_path;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PathService::Get(base::DIR_PROGRAM_FILESX86, &ie_path);
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ie_path = ie_path.Append(kIePath);
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandLine command_line(ie_path);
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  command_line.AppendArg(kChromeInstallUrl);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::LaunchOptions options;
2491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  options.as_user = token_scoped.Get();
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::LaunchProcess(command_line, options, NULL);
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns false if the print job is being run in a context
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that shouldn't be launching Chrome.
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ValidateCurrentUser() {
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HANDLE token = NULL;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetUserToken(&token)) {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we can't get the token we're probably not impersonating
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the user, so validation should fail.
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedHandle token_scoped(token);
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DWORD session_id = 0;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DWORD dummy;
2671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (!GetTokenInformation(token_scoped.Get(),
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             TokenSessionId,
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             reinterpret_cast<void *>(&session_id),
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             sizeof(DWORD),
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             &dummy)) {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (session_id == 0) {
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath ReadPathFromRegistry(HKEY root, const wchar_t* path_name) {
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::RegKey gcp_key(HKEY_CURRENT_USER, kCloudPrintRegKey, KEY_READ);
284a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 data;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (SUCCEEDED(gcp_key.ReadValue(path_name, &data)) &&
2867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::PathExists(base::FilePath(data))) {
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return base::FilePath(data);
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base::FilePath();
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath ReadPathFromAnyRegistry(const wchar_t* path_name) {
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath result = ReadPathFromRegistry(HKEY_CURRENT_USER, path_name);
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!result.empty())
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ReadPathFromRegistry(HKEY_LOCAL_MACHINE, path_name);
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath GetChromeExePath() {
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath path = ReadPathFromAnyRegistry(kChromeExePathRegValue);
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!path.empty())
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return path;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return chrome_launcher_support::GetAnyChromePath();
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath GetChromeProfilePath() {
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath path = ReadPathFromAnyRegistry(kChromeProfilePathRegValue);
3087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!path.empty() && base::DirectoryExists(path))
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return path;
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base::FilePath();
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BOOL WINAPI Monitor2EnumPorts(HANDLE,
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              wchar_t*,
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              DWORD level,
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              BYTE*  ports,
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              DWORD   ports_size,
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              DWORD* needed_bytes,
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              DWORD* returned) {
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (needed_bytes == NULL) {
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "needed_bytes should not be NULL.";
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetLastError(ERROR_INVALID_PARAMETER);
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (level == 1) {
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *needed_bytes = sizeof(PORT_INFO_1);
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (level == 2) {
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *needed_bytes = sizeof(PORT_INFO_2);
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Level "  << level << "is not supported.";
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetLastError(ERROR_INVALID_LEVEL);
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *needed_bytes += static_cast<DWORD>(cloud_print::kPortNameSize);
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ports_size < *needed_bytes) {
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << *needed_bytes << " bytes are required.  Only "
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << ports_size << " were allocated.";
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetLastError(ERROR_INSUFFICIENT_BUFFER);
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ports == NULL) {
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "ports should not be NULL.";
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetLastError(ERROR_INVALID_PARAMETER);
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (returned == NULL) {
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "returned should not be NULL.";
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetLastError(ERROR_INVALID_PARAMETER);
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Windows expects any strings refernced by PORT_INFO_X structures to
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // appear at the END of the buffer referenced by ports.  Placing
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // strings immediately after the PORT_INFO_X structure will cause
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // EnumPorts to fail until the spooler is restarted.
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is NOT mentioned in the documentation.
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t* string_target =
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<wchar_t*>(ports + ports_size -
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cloud_print::kPortNameSize);
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (level == 1) {
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PORT_INFO_1* port_info = reinterpret_cast<PORT_INFO_1*>(ports);
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    port_info->pName = string_target;
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    StringCbCopy(port_info->pName,
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 cloud_print::kPortNameSize,
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 cloud_print::kPortName);
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PORT_INFO_2* port_info = reinterpret_cast<PORT_INFO_2*>(ports);
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    port_info->pPortName = string_target;
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    StringCbCopy(port_info->pPortName,
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 cloud_print::kPortNameSize,
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 cloud_print::kPortName);
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    port_info->pMonitorName = NULL;
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    port_info->pDescription = NULL;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    port_info->fPortType = PORT_TYPE_WRITE;
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    port_info->Reserved = 0;
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *returned = 1;
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TRUE;
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BOOL WINAPI Monitor2OpenPort(HANDLE, wchar_t*, HANDLE* handle) {
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (handle == NULL) {
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "handle should not be NULL.";
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetLastError(ERROR_INVALID_PARAMETER);
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  *handle = new PortData();
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TRUE;
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BOOL WINAPI Monitor2StartDocPort(HANDLE port_handle,
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 wchar_t* printer_name,
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 DWORD job_id,
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 DWORD,
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 BYTE*) {
396c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SetGoogleUpdateUsage(kGoogleUpdateProductId);
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (port_handle == NULL) {
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "port_handle should not be NULL.";
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetLastError(ERROR_INVALID_PARAMETER);
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (printer_name == NULL) {
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "printer_name should not be NULL.";
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetLastError(ERROR_INVALID_PARAMETER);
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ValidateCurrentUser()) {
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(abodenha@chromium.org) Abort the print job.
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PortData* port_data = reinterpret_cast<PortData*>(port_handle);
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  port_data->job_id = job_id;
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!OpenPrinter(printer_name, &(port_data->printer_handle), NULL)) {
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Unable to open printer " << printer_name << ".";
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We can continue without a handle to the printer.
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // It just means we can't get the job title or tell the spooler that
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the print job is complete.
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This is the normal flow during a unit test.
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    port_data->printer_handle = NULL;
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath& file_path = port_data->file_path;
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath app_data_dir = GetAppDataDir();
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (app_data_dir.empty())
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return FALSE;
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DeleteLeakedFiles(app_data_dir);
426a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!base::CreateDirectory(app_data_dir) ||
427a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      !base::CreateTemporaryFileInDir(app_data_dir, &file_path)) {
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Can't create temporary file in " << app_data_dir.value();
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
431a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  port_data->file = base::OpenFile(file_path, "wb+");
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (port_data->file == NULL) {
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Error opening file " << file_path.value() << ".";
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TRUE;
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BOOL WINAPI Monitor2WritePort(HANDLE port_handle,
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              BYTE* buffer,
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              DWORD buffer_size,
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              DWORD* bytes_written) {
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PortData* port_data = reinterpret_cast<PortData*>(port_handle);
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ValidateCurrentUser()) {
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(abodenha@chromium.org) Abort the print job.
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *bytes_written =
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<DWORD>(fwrite(buffer, 1, buffer_size, port_data->file));
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (*bytes_written > 0) {
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TRUE;
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BOOL WINAPI Monitor2ReadPort(HANDLE, BYTE*, DWORD, DWORD* read_bytes) {
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LOG(ERROR) << "Read is not supported.";
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *read_bytes = 0;
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetLastError(ERROR_NOT_SUPPORTED);
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return FALSE;
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BOOL WINAPI Monitor2EndDocPort(HANDLE port_handle) {
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ValidateCurrentUser()) {
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(abodenha@chromium.org) Abort the print job.
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PortData* port_data = reinterpret_cast<PortData*>(port_handle);
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (port_data == NULL) {
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetLastError(ERROR_INVALID_PARAMETER);
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (port_data->file != NULL) {
476a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    base::CloseFile(port_data->file);
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    port_data->file = NULL;
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool delete_file = true;
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 file_size = 0;
480a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    base::GetFileSize(port_data->file_path, &file_size);
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (file_size > 0) {
482a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base::string16 job_title;
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (port_data->printer_handle != NULL) {
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        GetJobTitle(port_data->printer_handle,
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    port_data->job_id,
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    &job_title);
4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!LaunchPrintDialog(port_data->file_path, job_title)) {
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        LaunchChromeDownloadPage();
4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        delete_file = false;
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (delete_file)
4957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::DeleteFile(port_data->file_path, false);
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (port_data->printer_handle != NULL) {
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Tell the spooler that the job is complete.
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetJob(port_data->printer_handle,
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           port_data->job_id,
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           0,
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           NULL,
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           JOB_CONTROL_SENT_TO_PRINTER);
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  port_data->Close();
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Return success even if we can't display the dialog.
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(abodenha@chromium.org) Come up with a better way of handling
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // this situation.
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TRUE;
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BOOL WINAPI Monitor2ClosePort(HANDLE port_handle) {
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (port_handle == NULL) {
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "port_handle should not be NULL.";
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetLastError(ERROR_INVALID_PARAMETER);
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  delete reinterpret_cast<PortData*>(port_handle);
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TRUE;
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VOID WINAPI Monitor2Shutdown(HANDLE monitor_handle) {
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (monitor_handle != NULL) {
5245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    delete reinterpret_cast<MonitorData*>(monitor_handle);
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BOOL WINAPI Monitor2XcvOpenPort(HANDLE,
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const wchar_t*,
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                ACCESS_MASK granted_access,
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                HANDLE* handle) {
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (handle == NULL) {
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "handle should not be NULL.";
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetLastError(ERROR_INVALID_PARAMETER);
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  XcvUiData* xcv_data = new XcvUiData();
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  xcv_data->granted_access = granted_access;
5394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  *handle = xcv_data;
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TRUE;
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DWORD WINAPI Monitor2XcvDataPort(HANDLE xcv_handle,
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 const wchar_t* data_name,
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 BYTE*,
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 DWORD,
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 BYTE* output_data,
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 DWORD output_data_bytes,
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 DWORD* output_data_bytes_needed) {
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XcvUiData* xcv_data = reinterpret_cast<XcvUiData*>(xcv_handle);
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD ret_val = ERROR_SUCCESS;
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((xcv_data->granted_access & SERVER_ACCESS_ADMINISTER) == 0) {
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERROR_ACCESS_DENIED;
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (output_data == NULL || output_data_bytes == 0) {
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERROR_INVALID_PARAMETER;
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't handle AddPort or DeletePort since we don't support
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // dynamic creation of ports.
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (lstrcmp(L"MonitorUI", data_name) == 0) {
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DWORD dll_path_len = 0;
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath dll_path(GetPortMonitorDllName());
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dll_path_len = static_cast<DWORD>(dll_path.value().length());
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (output_data_bytes_needed != NULL) {
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *output_data_bytes_needed = dll_path_len;
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (output_data_bytes < dll_path_len) {
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return ERROR_INSUFFICIENT_BUFFER;
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ret_val = StringCbCopy(reinterpret_cast<wchar_t*>(output_data),
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               output_data_bytes,
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               dll_path.value().c_str());
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERROR_INVALID_PARAMETER;
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret_val;
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BOOL WINAPI Monitor2XcvClosePort(HANDLE handle) {
5815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  delete reinterpret_cast<XcvUiData*>(handle);
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TRUE;
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BOOL WINAPI MonitorUiAddPortUi(const wchar_t*,
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               HWND hwnd,
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const wchar_t* monitor_name,
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               wchar_t**) {
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HandlePortUi(hwnd, monitor_name);
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TRUE;
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BOOL WINAPI MonitorUiConfigureOrDeletePortUI(const wchar_t*,
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             HWND hwnd,
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             const wchar_t* port_name) {
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HandlePortUi(hwnd, port_name);
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TRUE;
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}   // namespace cloud_print
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MONITOR2* WINAPI InitializePrintMonitor2(MONITORINIT*,
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         HANDLE* handle) {
6044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (handle == NULL) {
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetLastError(ERROR_INVALID_PARAMETER);
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  cloud_print::MonitorData* monitor_data = new cloud_print::MonitorData;
6094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  *handle = monitor_data;
6104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!cloud_print::kIsUnittest) {
6114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Unit tests set up their own AtExitManager
6124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    monitor_data->at_exit_manager.reset(new base::AtExitManager());
6134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Single spooler.exe handles verbose users.
6144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    PathService::DisableCache();
6154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return &cloud_print::g_monitor_2;
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MONITORUI* WINAPI InitializePrintMonitorUI(void) {
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return &cloud_print::g_monitor_ui;
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
623